2015-12-11 54 views
0

我也看到,它已经在这里问: C++: Template Parameter Cyclic Dependency模板参数循环依赖

但我不太明白接受的答案在那里。

因此,让我重申这里的问题。

比方说,我有:

template <class P> 
class Consumer { 
    P m_producer; 
public: 
void consume(char* data, uint32_t length) { 
    if (/* some error condition */) { 
     m_producer.errorCallback(); 
    } 
} 
} 

template <class C> 
class Producer { 
    C m_consumer; 
void produce() { 
    char* someData; 
    uint32_t length; 
    m_consumer.consume(someData, length); 
} 
} 

// Pseudocode -- not valid C++. 
Producer<Consumer> c; 
Consumer<Producer> p; 

正如你可以看到,生产者需要调用消费者,和消费者需要调用生产者;并且两者都依赖于其他模板参数。

不使用任何虚拟类(接口)来解决这种模板参数的最佳方法是什么?

在此先感谢。

+0

一个需要在另一个之前创建,并将其作为参考传递给另一个,将其作为指针存储。 – Simple

+0

为什么消费者是生产者的模板参数?你真的想要一个只能为特定消费者生产东西的生产者吗?一旦你放弃这个限制,就再也没有圈子了。 – user463035818

+0

@ tobi303因为我有不同的消费者,我想避免虚拟表 – Hei

回答

1

与任何这类概念问题一样,答案是:重构,重构,重构。循环模板参数依赖性指示业务逻辑中的概念性错误。

考虑一下将大致是内存布局,如果这种相关性在那里接受:

// Not C++ 

Producer a { 
    m_consumer { 
    m_producer { // Not 'a', this is another producer. 
     m_consumer { // With an also different consumer inside. 
     // ... and it continues forever. 
     } 
    } 
    } 
} 

相反,让我们diferently想想:如果我们只需要一个消费者和一个生产者连接在一起,它不仅使意识到它们是同一个数据结构的一部分。我们可以使用奇异递归模板模式,以避免生产商的模板参数:

#include <iostream> 

template<typename Producer> 
class Consumer { 
    Producer& p; 
public: 
    bool error{false}; 
    Consumer(Producer& p_) 
     :  p(p_) 
    {} 
    void consume(char* data, size_t lenght) { 
    if (!data) { 
     p.error_callback(); 
     error = true; 
    } 
    } 
}; 

class Producer : public Consumer<Producer>{ 
public: 
    Producer() 
     : Consumer<Producer>(*this) 
    {} 
    Consumer<Producer>& consumer() {return *this;} 
    void produce() { 
    char* some_data(nullptr); 
    int length{0}; 
    consume(some_data, length); 
    } 
    void error_callback() { 
    std::cout << "Error\n"; 
    } 
}; 

int main() { 
    Producer producer; 
    auto& consumer = producer.consumer(); 
    producer.produce(); 
    if (consumer.error) { 
    std::cout << "Got error from consumer"; 
    } 
} 

让我们考虑的main()的两个第一线的内存布局:

// Not C++ 
Producer a { 
    consumer { // A producer implicitly has a consumer, since it inherits from it. 
    reference to a; 
    } 
} 
reference to consumer; 

当然,这只解决你陈述的问题。但真正的教训是:尝试考虑您期望的内存布局,这将帮助您找出如何在代码中表达它。

+0

了解了很多(特别是好奇的循环模板,虽然它不是我可以用在我的问题,它有一些有趣的特点)。感谢您的输入! – Hei

+0

实际上,有一个有趣的解决方案http://qscribble.blogspot.com/2008/06/circular-template-references-in-c.html不确定在C++ 11中是否有更好的方法来实现这一点和C++ 14现在可用。 – Hei