рекурсивная проблема шаблона C ++ - PullRequest
1 голос
/ 25 октября 2010

Скажем, у меня есть шаблонный класс, который берет сообщения из источника, делает с ними что-то умное и затем отправляет их в приемник:

template <typename Source, typename Sink>
class MsgHandler
{
MsgHandler(Source* pSource)
: m_pSource(pSource)
{
  m_pSource->setHandler(this);
}
};

//Now the definition of the Source:

template <typename Handler>
class Source
{
void setHandler(Handler* pHandler)
{
  m_pHandler = pHandler;
}
};

Все хорошо, но сейчас я не могу сделать Источником или Обработчиком. Например:

MsgHandler<FileSource<MsgHandler<FileSource.... recursing parameters...
FileSource<MsgHandler<FileSource<MsgHandler.... same problem when trying to build a source

Есть ли способ решить эту проблему без использования виртуального базового класса для обработчика?

Решение виртуального базового класса:

class MyHandler
{
virtual ~MyHandler() {};
virtual void handleSomething() = 0;
};

template <typename Source, typename Sink>
class MsgHandler : public MyHandler
{
  MsgHandler(Source* pSource)
  : m_pSource(pSource)
  {
    m_pSource->setHandler(this);
  }
  void handleSomething() {}
 };

class Source
{
void setHandler(MyHandler* pHandler)
{
m_pHandler = pHandler;
}
};

Ответы [ 3 ]

2 голосов
/ 26 октября 2010

Вы можете использовать шаблонный параметр для исходного параметра вашего обработчика:

class MySink;
template <template<typename Handler> class Source, typename Sink>
class MsgHandler
{
    Source<MsgHandler>* m_pSource;

    MsgHandler(Source<MsgHandler>* pSource)
    : m_pSource(pSource)
    {
      m_pSource->setHandler(this);
    }
};

//Now the definition of the Source:

template <typename Handler>
class Source
{
    void setHandler(Handler* pHandler)
    {
      m_pHandler = pHandler;
    }
};

//Now you can define variables like this
MsgHandler<Source, MySink> myHandler;

Конечно, для этого требуется, чтобы параметр Source MsgHandler был шаблоном с ровно одним параметром (обработчиком), но есливы можете жить с этим ограничением, это решит вашу проблему определения (в противном случае вы можете (или можете не зависеть от того, что именно вы пытаетесь) использовать некоторый дополнительный шаблон foo, чтобы обойти это ограничение (создав другой шаблон, который принимает обработчик какпараметр и имеет typedef для соответствующего SourcesType.

В этом сценарии также может быть хорошей идеей добавить typedef Source<MsgHandler> SourceType в MsgHandler, чтобы сделать Source-Instantiation видимым для вызывающей стороны (вместо этоготребование программиста угадать, что MsgHandler будет создавать экземпляр Source.

1 голос
/ 25 октября 2010

Похоже, Handler не должен ничего знать о Source.Как насчет простой линейной зависимости:

template <typename Sink>
class Handler {
private:
    Sink* sink; // get this pointer in the constructor?
public:
    void handle( const Msg& m ) {
        // processing
        sink->accept( m );
    }
};

template <typename Handler>
class Source {
private:
    Handler* handler; 
public:
    void genMessage() {
        Msg m;
        // get message off the wire?
        handler->handle( m );
    }
};

Может также быть изменен, чтобы иметь "обработку" и "погружение" как политики .

1 голос
/ 25 октября 2010

Я не понимаю, почему ваш Source должен быть параметризован в своем обработчике.Если Source и Handler действительно должны быть тесно связаны в способе, который вы описываете, то не похоже, что шаблоны покупают вас за пределами определения интерфейса.Мне кажется, вы могли бы просто иметь не шаблонный Source класс, который инкапсулирует Handler<Source, Sink>.

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