1

ビジターパターンを使用してオブジェクトのコンテンツをシリアル化しようとしています。しかし、私が打っている問題の1つは、文字列にアクセスしているときです。私の文字列は、STLのbasic_stringに似たテンプレートタイプです。だから次のようなもの:

basic_string<char_type, memory_allocator, other_possible_stuff> \\ many variations possible!

非常に多くの異なるテンプレート文字列タイプを使用できるため、それらを訪問者インターフェイスに追加することはできません。それはばかげているでしょう。しかし、C ++では仮想メソッドでテンプレートパラメーターを使用できないため、VisitStringメソッドにテンプレートを追加できません。

では、これを回避するための私のオプションは何ですか?

編集:私はいくつかの基本的なコードを追加しました

class IVisitor
{
public: 
     virtual void VisitString(some_kind_of_string_type string) = 0; // this is what I want in theory
};

class MyObject
{
public:
    typedef basic_string<char8, myAllocator, some_flag> MyStringType;
    Accept(IVisitor* visitor)
    {
        visitor->VisitString(mString); 
    }
private:
   MyStringType string;
};

class MyOtherObject
{
public:
    typedef basic_string<char16, myOtherAllocator, some_other_flag> MyOtherStringType;
    Accept(IVisitor* visitor)
    {
        visitor->VisitString(mString); 
    }
private:
   MyOtherStringType string;
};


class Reader : public IVisitor
{ 
public:
    virtual void VisitString(some_kind_of_string_type string)
    {
         // read some data, give it to the string
    }
}
4

7 に答える 7

1

実行時ポリモーフィズムが必要ですか?

struct object {
   template <typename Visitor>
   void accept( Visitor & v )
   {
      v( x );
      v( a );
   }

   int x;
   std::string a;
};
struct complex_object {
   template <typename Visitor>
   void accept( Visitor & v ) {
      v( i );
      o.accept(v); // [1]
   }
   int i;
   object1 o;
};

struct DumpScreenVisitor {
   void operator()( int x ) { std::cout << x << std::endl; }
   template <typename char_t, typename traits_t, typename alloc_t>
   void operator()( std::basic_string<char_t, traits_t, alloc_t> const & str )
   {
      std::cout << str << std::endl;
   }
};

[1] の呼び出しは、最も特殊化されていないビジターでv( o )汎用テンプレート化されたものに変換できます。operator()

template <typename O>
void DumpScreenVisitor::operator()( O & o )
{
   o.accept( *this );
}

ただし、これは他のビジターの実装と干渉する可能性があります (たとえば、上記のビジターは単一のテンプレート化されたメソッドで実装できます)。

struct DumpScreenVisitor {
   template <typename T>
   void operator()( T const & t ) {
      std::cout << t << std::endl;
   }
};

そのため、最終的にはいずれかの方法で妥協する必要があります。

このアプローチは、boost::variant ビジター実装 (参照してください) に似ていますが、boost::variant は階層ではなく単一のクラスであるという違いがあります。

于 2010-03-31T20:19:25.343 に答える
1

結局、私は少し異なるアプローチで行きました。テンプレート化されたメソッドでビジターを使用することを期待する代わりに (これはもちろん不可能です)、ビジターのようなクラスをテンプレート パラメーターとしてオブジェクトの visit メソッドに渡すことにしました。完全に単純化された例:

class SomeKindOfVisitor // doesn't need to derive from a base class. 
{
     template <class StringClass>
     void VisitString(StringClass& string) // I get to keep templated methods
}


class MyObject
{
typedef basic_string<char8, myAllocator, some_flag> MyStringType;

public:

   template <class VisitorClass>
   void Accept(VisitorClass& visitor)
   {
       vistior.VisitString<MyStringType>(mMyString);
   }
private:
    MyStringType mMyString;
}

このメソッドを使用すると、オブジェクトにあらゆる種類の「訪問者」を渡すことができる一方で、テンプレート化された文字列を引き続き使用できます。

于 2010-04-06T14:19:20.080 に答える
0

問題は、文字列のテンプレート パラメーターが非常に異なる可能性があるため、1 つのシリアル化方法を適用できるかどうかです。その場合、シリアライゼーションに必要なすべての情報を均一な表現に抽出するテンプレート化されたコンストラクターを持つアダプターを作成できます。次に、アダプターを使用してシリアライザーにアクセスします。

編集:コードを追加した後でも、アダプターが問題を解決できると思いますが、その逆です。you メソッドAcceptで、ローカル アダプタを作成し、Visitor. が変更されたら、アダプタでVisitorテンプレート メソッドを使用してextractToString、情報を特定の文字列バージョンに変換できます。これにより、文字列テンプレートのインスタンス化をどのように処理する必要があるかによって、アダプターの終了が複雑になる場合があります。

于 2010-03-31T19:11:01.000 に答える
0

以下で検討できるかもしれませんが、この場合、ビジターメカニズムを異なるビジタークラスに分離する必要があります。WStringVisitor と StringVisitor は、異なる Visitor セマンティクスの単なる例です。

#include <string>

#include <iostream>

using namespace std;

template <typename stringType>
class IVisitor{
public:
    virtual void visit(stringType _string)=0;
};

class StringVisitor: public IVisitor<string>{
public:
    void visit(string str){
        cout<<"This is std::string implementation: "<< str << endl;
    }
};
class WStringVisitor: public IVisitor<basic_string<wchar_t>>{
public:
    void visit(basic_string<wchar_t> str){
        //wprintf(L"This wide implementation : %S", str.c_str());
        wcout<<"This is WString Visitor: "<< str << endl;
    }
};

class MyObject{
public:
    typedef basic_string<char> MyStringType;

    void accept(IVisitor<MyStringType>& visitor){
        visitor.visit("TEST STRING");
    }
};

class MyOtherObject
{
public:
    typedef basic_string<wchar_t> MyOtherStringType;
    void accept(IVisitor<MyOtherStringType>& visitor)
    {
        visitor.visit(L"TEST WSTRING"); 
    }

};


int _tmain(int argc, _TCHAR* argv[])
{
    MyObject acceptor;
    MyOtherObject otheracceptor;
    StringVisitor visitor;
    WStringVisitor wvisitor;
    acceptor.accept(visitor);
    //otheracceptor.accept(visitor); compile error
    otheracceptor.accept(wvisitor);
    return 0;
} 
于 2010-04-02T10:57:42.913 に答える
0

ここでの根本的な問題は、Visitor パターンがすべて仮想関数に関するものであり、関数テンプレートを使用して文字列を集めていることだと思います。そして、これらは簡単には混ざりません。実際、この 2 つを混在させる唯一の方法は、type eraseです。

このテクニックを使ってやりたいことを実現する方法が見つからない場合、方法は見つからないと思います。

于 2010-04-06T08:06:09.740 に答える
0

ビジターは、文字列の基本的な表現 (char* / wchar*) のみを処理する必要があります。

その後、キャストを処理するのは accept メソッド次第です。

于 2010-03-31T19:24:52.497 に答える
0

すべての文字列クラスは異なる型であるため、ある程度妥協する必要があります (仮想メソッドを使用した共通のサブタイプ、文字列、またはアダプター、または異なる型ごとにビジターへのメソッドの追加)。妥協を許さない場合は特に、ジェネリック プログラミングと oo を混在させるのは面倒です。

例えば。

class string_tag { /* common visitor interface */ };

template<typename char_t, ...> class basic_string : public string_tag {};

class IVisitor
{
public: 
     virtual void VisitString(string_tag& string) = 0; // this is what I want in theory
};

class MyObject
{
public:
    typedef basic_string<char8, myAllocator, some_flag> MyStringType;
    Accept(IVisitor* visitor)
    {
        visitor->VisitString(string); 
    }
private:
   MyStringType string;
};

class MyOtherObject
{
public:
    typedef basic_string<char16, myOtherAllocator, some_other_flag> MyOtherStringType;
    Accept(IVisitor* visitor)
    {
        visitor->VisitString(string); 
    }
private:
   MyOtherStringType string;
};


class Reader : public IVisitor
{ 
public:
    virtual void VisitString(string_tag& string)
    {
         // read some data, give it to the string
    }
}
于 2010-03-31T19:51:17.497 に答える