模板化基类还具有公共基类指针吗?

时间:2019-03-31 09:04:24

标签: c++ templates polymorphism type-erasure

我正在尝试构建一个执行图,其中每个节点可以产生不同类型的多个输出并使用不同类型的多个输入。数据通过队列在节点之间传输。

要连接2个节点,一个节点的输入类型必须连接到另一节点的相同输出类型。例如,尝试将一个节点的int输出连接到另一节点的double输入,将会产生编译错误。

所有节点都将从具有execute()方法的基类派生,该方法从不同的输入类型读取并写入不同的输出类型。目前,我有这样的东西-

struct Node {
    virtual void execute() = 0;
};

struct IntegerGeneratorNode: public Node {
    void execute() {
        while(some_condition_is_not_met) {
           // write() will do std::queue<int>::push();
           int_out.write(some_rand_integer);
        }
    }
    Output<int> int_out;
};

struct FloatGeneratorNode: public Node {
    void execute() {
        while(some_condition_is_not_met) {
           // write() will do std::queue<float>::push();
           float_out.write(some_rand_float);
        }
    }
    Output<float> float_out;
};

struct SinkNode: public Node {
    void execute() {
        while(some_condition) {
           int val = int_inp.read(); // invokes queue<int>::front()+pop()
           float f_val = float_inp.read();
           // Do something with val and f_val.
        }
    }
    Input<int> int_inp;
    Input<float> float_inp;
};

Input<T>是一个模板类,具有类型queue的{​​{1}}。 T是模板类,具有指向类型Output<T>的{​​{1}}的指针。要连接2个节点,我要做类似的事情-

queue

这很好,但是我还有另一个要求-在将T方法调用-Node *int_node = IntegerGeneratorNode(); Node *float_node = FloatGeneratorNode(); Node *sink_node = SinkNode(); int_node.int_out.connect(sink_node.int_inp); float_node.float_out.connect(sink_node.float_inpt); std::thread int_thread([](Node *node){ node->execute(); }, int_node); std::thread float_thread([](Node *node){ node->execute(); }, float_node); std::thread sink_thread([](Node *node){ node->execute(); }, sink_node); 之前,对Input<T>的所有Node执行一些操作。如您所见,具有命名变量不会扩展。您必须在所有变量上添加一个execute。我需要某种循环。

一个想法是拥有Input<T>::doSomePreProcessing()类型的.doSomething并使用C ++ 17 tuple迭代元组。但是我的另一个主要要求是派生类是客户端代码,而基类是框架代码。必须从基类进行所有预处理,以减轻派生类的负担。为此,我需要像这样将元组移动到基类-

Input

此变化产生了2种副作用

  1. 现在已经对基类进行了模板化,我不再具有在图的节点上调用std::apply方法所需的公共基类指针。

  2. template<typename T> struct Node { virtual void execute() = 0; void doExecute { preprocess(some_tuple); execute(); } T inputs() { return input_tuple; } T input_tuple; }; template<typename T> struct SinkNode: public Node<T>{ ... }; // Call site. SinkNode<std::tuple<int,float>> sink_node; 难以实现。理想情况下,我正在寻找的是

doExecute

但是由于connect不再可用,所以我不能这样做。

我如何对基类中的输入进行所有处理,但有一个通用的基类指针?换句话说,没有模板吗?

1 个答案:

答案 0 :(得分:1)

想到了几种方法:

  1. virtual void execute() = 0拆分为一个单独的基类,然后从该基类中派生出不同的模板化基类。
  2. 应用装饰器模式:只需创建一个包装另一个Node类的Node类。调用外部execute()时,请预处理输入,然后调用内部execute()
  3. 使用多重继承。一个基类可以提供execute()接口,另一个可以提供预处理接口。这与第一个变体相似,只是这两个部分没有堆叠在一起,而是在同一高度上彼此相邻。