C ++ Circular #include未正确声明前向声明

时间:2015-09-06 09:48:10

标签: c++ c++11 include circular-dependency

我知道如何解决基本循环依赖示例,有两个类,每个类都需要知道另一个存在。
但是,我现在处于这样的情况,其中示例更复杂,并且前向声明不是什么,可以解决该问题。

考虑这三个文件

// my_thread.hpp
template<typename Function> class my_thread;

template<typename Return, typename... Input>
struct my_thread<Return(Input...)>
{
    void somefunction() { thread_manager::static_function(); }
}
// thread_manager.hpp
struct thread_manager
{
    static void static_function() { }
    std::list<some_class::thread_type> threads;
}
// some_class.hpp
struct some_class
{
    using thread_type = my_thread<int(some_class*)>
}

现在,显然my_thread.hpp需要整个thread_manager(或至少它的功能?)。 thread_manager需要来自using的{​​{1}}指令,some_class取决于some_class。由于STL容器需要完整的类型模板参数,因此我无法转发声明my_thread。我甚至不能提出my_thread的定义,因为它是模板功能,需要放在标题中 我的问题是,如何解决这种循环依赖?

有趣的是,MSVC不需要my_thread<T>::somefunction() my_thread.hpp #include "thread_manager" in thread_manager`。

2 个答案:

答案 0 :(得分:1)

解决这个问题的一种方法是将线程管理器作为模板参数注入:

// my_thread.hpp
template<typename ThreadManager, typename Function> class my_thread;

template<typename ThreadManager, typename Return, typename... Input>
struct my_thread<ThreadManager, Return(Input...)>
{
    void somefunction() { ThreadManager::static_function(); }
}

你的some_class必须通过线程管理器,但它对线程管理器一无所知,所以你必须将线程管理器注入some_class

// some_class.hpp
template<typename ThreadManager>
struct some_class
{
    using thread_type = my_thread<ThreadManager, int(some_class*)>;
};

最后,线程管理器可以将自己注入some_class

// thread_manager.hpp
struct thread_manager
{
    static void static_function() { }
    std::list<my_thread<thread_manager, int(int)>> threads;
}

使用这种结构不再直接依赖于线程管理器。

另外,您可能希望在某些单线程上下文中使用some_class。在这种情况下,您可以创建一个虚拟ThreadManager,它提供与thread_manager相同的接口但不执行任何操作,并将此类设置为默认模板参数。

答案 1 :(得分:0)

#include <list>

// my_thread.hpp
template<typename Function> class my_thread;

// thread_manager.hpp
struct thread_manager
{
    static void static_function() { }
    std::list<my_thread<int(int)>> threads;
} ;

template<typename Return, typename... Input>
struct my_thread<Return(Input...)>
{
    void somefunction() { thread_manager::static_function(); }
} ;

另一种变体:在模板中保留一些功能的声明 并在单独的文件中实现它。