具有动态回调函数类型的C ++模板类

时间:2018-11-15 02:20:39

标签: c++ c++11 templates callback pure-virtual

在下面的代码中,我希望用户能够创建具有特定类型(例如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 :(得分:2)

  

消耗方法来自基类,必须重写它们。 [...]我该如何做?

我认为可能的解决方案是开发两种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
}