Обработка шаблонов в C ++ для шаблонных строковых типов? - PullRequest
1 голос
/ 31 марта 2010

Я пытаюсь использовать шаблон посетителя для сериализации содержимого объектов. Однако одна загвоздка, которую я поражаю, - это когда я посещаю струны. Мои строки имеют шаблонный тип, похожий на basic_string в STL. Так что-то вроде:

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

Поскольку у меня может быть очень много разных типов шаблонных строк, я не могу пойти и добавить их в свой интерфейс посетителя. Это было бы смешно. Но я не могу добавить шаблоны в свой метод VisitString, поскольку C ++ не позволяет использовать параметры шаблонов в виртуальных методах.

Так, каковы мои варианты обойти это?

РЕДАКТИРОВАТЬ: я добавил базовый код

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
    }
}

Ответы [ 7 ]

1 голос
/ 01 апреля 2010

Вам нужен полиморфизм во время выполнения?

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 :: variable (вы можете захотеть взглянуть на него), с той разницей, что boost :: variable является отдельным классом, а не иерархией.

1 голос
/ 06 апреля 2010

В итоге я пошел с немного другим подходом. Вместо того чтобы надеяться использовать посетителя с шаблонными методами (что, конечно, невозможно), я решил передать подобный посетителю класс в качестве параметра шаблона для метода посещения моего объекта. Полностью упрощенный пример:

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;
}

С помощью этого метода я по-прежнему могу использовать мои шаблонные строки, но при этом могу передавать любые виды "посетителей" моим объектам.

0 голосов
/ 06 апреля 2010

Я думаю, что основная проблема здесь заключается в том, что шаблон Visitor - это все о виртуальных функциях, в то время как вы строите свои строки через шаблоны функций. И это просто не легко смешать. На самом деле, я могу думать только о том, как смешать эти два типа: тип стирания .

Если вы не найдете способ сделать то, что вы хотите, используя эту технику, я не думаю, что вы найдете способ.

0 голосов
/ 02 апреля 2010

Может быть, вы можете рассмотреть ниже, но в этом случае вам нужно разделить механизмы посетителей для разных классов посетителей. 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;
} 
0 голосов
/ 31 марта 2010

Поскольку все ваши строковые классы относятся к разным типам, вам потребуется определенный уровень компромисса (либо общий подтип, с виртуальными методами для ваших строк, либо адаптер, либо добавление метода для каждого различного типа посетителю). Смешивать дженерик-программирование и oo может быть больно, особенно если вы не принимаете компромиссы.

* * 1004 Eg. * * 1005
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
    }
}
0 голосов
/ 31 марта 2010

ваш посетитель должен обрабатывать только базовое представление строк (char * / wchar *);

это затем до метода accept для обработки приведения.

0 голосов
/ 31 марта 2010

Ну, вопрос в том, что параметры шаблона в вашей строке могут быть такими разными, можете ли вы применить один единственный метод сериализации для них? Если это так, вы можете написать адаптер с шаблонным конструктором, который извлекает всю информацию, необходимую для сериализации, в единое представление. Затем вы посещаете сериализатор с адаптером.

РЕДАКТИРОВАТЬ: После того, как вы добавили свой код, я все еще думаю, что адаптер может решить вашу проблему, только наоборот. В вашем Accept -методе создайте локальный адаптер и передайте его Visitor. Когда Visitor изменил его, вы можете использовать шаблонный метод extractToString на адаптере, который преобразует информацию в конкретную версию строки. Это может усложнить завершение работы адаптера в зависимости от того, насколько разными должны быть обработаны экземпляры строкового шаблона.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...