Шаблонный класс C ++ с динамическим типом функции обратного вызова - PullRequest
0 голосов
/ 15 ноября 2018

В приведенном ниже коде я хочу, чтобы пользователь мог создавать потребительский класс с определенным типом, например, Consumer<StateA>, чтобы его функция обратного вызова могла правильно обрабатывать тип, который он ему дал. Однако в приведенном ниже коде компилятор жалуется, потому что во время компиляции вызов функции в методе потребления StateB не генерируется. Методы потребления происходят из базового класса и должны быть переопределены.

template <class T>
class Consumer : ConsumerBase
{
    public:
        Consumer(std::function<void(T&)> _callback){
            callback = _callback;
        }
        virtual void consume(StateA& state) { 
            callback(state);
        }
        virtual void consume(StateB& state) { 
            callback(state);
        }
    private:
        std::function<void(T&)> callback; 
};

Базовый класс:

class ConsumerBase
{
   public:
      virtual void consume(StateA& state) = 0;
      virtual void consume(StateB& state) = 0;
};

Как я могу сделать эту работу?

1 Ответ

0 голосов
/ 15 ноября 2018

Методы потребления происходят из базового класса и должны быть переопределены.[...] Как я могу заставить эту работу работать?

Я полагаю, что возможное решение - это разработать пару consume_h() ("потребление помощника") методов.

первый - точное соответствие для T (тип шаблона класса), который вызывает функцию обратного вызова

    void consume_h (T & state)
     { callback(state); }

второй - это шаблонная версия, которая ничего не делает

    template <typename U>
    void consume_h (U &)
     { }

Теперь вы можете переопределить оба виртуальных метода, вызывающих consume_h()

    virtual void consume (StateA & state)
     { consume_h(state); }

    virtual void consume (StateB & state)
     { consume_h(state); }

Таким образом, виртуальный метод, соответствующий T, вызывает consume_h(), который вызывает обратный вызов;другой вызывает шаблон consume_h(), который ничего не делает.

Ниже приведен полный пример компиляции

#include <functional>

struct StateA { };
struct StateB { };

struct ConsumerBase
 {
   virtual void consume (StateA &) = 0;
   virtual void consume (StateB &) = 0;
 };

template <typename T>
class Consumer : ConsumerBase
{
    public:
        Consumer (std::function<void(T&)> cb0) : callback{cb0}
         { }

        void consume_h (T & state)
         { callback(state); }

        template <typename U>
        void consume_h (U &)
         { }

        virtual void consume (StateA & state)
         { consume_h(state); }

        virtual void consume (StateB & state)
         { consume_h(state); }

    private:
        std::function<void(T&)> callback; 
};

int main()
{
   Consumer<StateA>  csa{[](StateA &){ std::cout << "A" << std::endl; }};
   Consumer<StateB>  csb{[](StateB &){ std::cout << "B" << std::endl; }};

   StateA  sa;
   StateB  sb;

   csa.consume(sa);  // print A
   csb.consume(sb);  // print B
}
...