函数的参数有两个模板类型,但只关心一个

时间:2015-11-17 17:34:40

标签: c++ templates

我正在开发一个工作流系统,用于在生产者消费者模型中将任务连接在一起。这个想法是你有一个或多个任务正在生成和消费彼此的数据。我已经实现了任务,现在我试图将它们连接在一起。为了帮助管理这些任务,我创建了一个连接器类,可以将一个或多个生产者任务与一个或多个使用者任务有效连接。

问题是,我正在模仿这些类,以便Task<T, U>可以定义为某个具有输入类型T(消耗T)和输出类型U(生成U)的任务。

我在下面定义了这个任务:

template <class T, class U>
class Task {
    static_assert(std::is_base_of<AbsData, T>::value, "T must derive from AbsData");
    static_assert(std::is_base_of<AbsData, U>::value, "U must derive from AbsData");
...
}

接下来将两个任务连接在一起,我使用一个连接器。这在某种程度上代表了两个任务之间的优势。该连接器有两个列表:std::list<Task<AbsData, T> *> *producerTasks;std::list<Task<T, AbsData> * consumerTasks;。我试图做的基本上是忽略一个任务的模板类型之一,并且说我只关心类型T并希望在另一个类型中拥有任何类型。

template <class T>
class Connector {
    static_assert(std::is_base_of<AbsData, T>::value, "T must derive from AbsData");
public:

 // Is it possible to set up a function so I effectively pass any parent AbsData, but hold onto type T?
 void addProducerTask(Task<AbsData, T> *producer) {
    this->producerTasks->push_front(producer);
    this->producerTaskCount = this->producerTasks->size();
    producer->setOutputConnector(this);
}

private:
    std::list<Task<AbsData, T> *> *producerTasks;
    std::list<Task<T, AbsData> * consumerTasks;
}

主要问题是addProducerTask是否可以传入一个具有某种类型的AbsData和类型T的任务?

以下是一个例子:

// FFTData inherits AbsData
Connector<FFTData> *connector = new Connector<FFTData>();
Task<FFTData, FFTData> *task = new Task<FFTData, FFTData>(...);
connector->addProducerTask(task);

此示例出现以下编译时错误:Parameter type mismatch: Class 'Task<FFTData, FFTData>' is not compatible with class 'Task<AbsData, FFTData>'

编辑: 我决定重新设计实现以模板化函数。

 template <class U>
 void addProducerTask(Task<U, T> *producer) {
    incrementProducerCount();
    producer->setOutputConnector(this);
}

没有必要跟踪连接器所连接的任务,而只需要确保连接器已添加到任务中,因此任务可以从连接器生成/使用数据。尽管能够拥有模板化成员变量会很好,但由于缺少类型擦除,似乎需要进行此返工。

如果我想在中间添加连接器边缘,这也很有效:

template <class Q, class R>
void addEdge(Task<Q, T> *producer, Task<T, R> *consumer) {
    producer->setOutputConnector(this);
    consumer->setInputConnector(this);

    incrementInputTaskCount();
};

1 个答案:

答案 0 :(得分:1)

  

此示例获取以下编译时错误:参数类型   不匹配:Class&#39; Task<FFTData, FFTData>&#39;与班级不兼容   &#39; Task<AbsData, FFTData>'

这是因为实际的Task<AbsData, FFTData>Task<FFTData, FFTData>是不相关的类型,无论关系如何

// FFTData inherits AbsData

他们实际的第一个类型参数。

要解决此问题,您可以例如使它们相关(如果它与您设计的其他部分兼容):

#include <type_traits>
#include <list>

struct AbsData {};
struct FFTData : public AbsData{};


template <class T, class U>
class Task : public Task<AbsData, U> {
    static_assert(std::is_base_of<AbsData, T>::value, 
                  "T must derive from AbsData");
    static_assert(std::is_base_of<AbsData, U>::value, 
                  "U must derive from AbsData");
};

template <class U>
class Task<AbsData, U> {};

template <class T>
class Connector {
    static_assert(std::is_base_of<AbsData, T>::value, 
                  "T must derive from AbsData");
public:

 // Is it possible to set up a function so I effectively pass 
 // any parent AbsData, but hold onto type T?
 void addProducerTask(Task<AbsData, T> *producer) {
/*    this->producerTasks->push_front(producer);
    this->producerTaskCount = this->producerTasks->size();
    producer->setOutputConnector(this);*/
}

private:
    std::list<Task<AbsData, T> *> *producerTasks;
    std::list<Task<T, AbsData> *> consumerTasks;
};

int main() {
    Connector<FFTData> *connector = new Connector<FFTData>();
    Task<FFTData, FFTData> *task = new Task<FFTData, FFTData>();
    connector->addProducerTask(task);    

    return 0; 
}

live在Coliru的