C++ Circular #include 前向声明未修复
C++ Circular #include where forward declaration is not fix
我知道如何解决基本的循环依赖示例,有两个 类,每个都需要知道另一个存在。
但是,我现在的情况是,示例更复杂,前向声明不是可以解决该问题的东西。
考虑这三个文件
// 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
需要来自 some_class
的 using
指令并且 some_class
依赖于 my_thread
。由于 STL 容器需要完整的类型模板参数,我无法转发声明 my_thread
。我什至无法给出 my_thread<T>::somefunction()
的定义,因为它是模板函数,需要放在 header.
中
我的问题是,如何解决这种循环依赖?
有趣的是,MSVC 不需要 #include "thread_manager" in
my_thread.hppfor some reason. I don't know how it knows about
thread_manager`。
解决这个问题的一种方法是将线程管理器作为模板参数注入:
// 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
。在这种情况下,您可以创建一个提供与 thread_manager
相同界面但不执行任何操作的虚拟 ThreadManager
,并将此 class 设置为默认模板参数。
#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(); }
} ;
另一种变体:在模板中保留 somefunction 的声明
并在单独的文件中实现它。
我知道如何解决基本的循环依赖示例,有两个 类,每个都需要知道另一个存在。
但是,我现在的情况是,示例更复杂,前向声明不是可以解决该问题的东西。
考虑这三个文件
// 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
需要来自 some_class
的 using
指令并且 some_class
依赖于 my_thread
。由于 STL 容器需要完整的类型模板参数,我无法转发声明 my_thread
。我什至无法给出 my_thread<T>::somefunction()
的定义,因为它是模板函数,需要放在 header.
中
我的问题是,如何解决这种循环依赖?
有趣的是,MSVC 不需要 #include "thread_manager" in
my_thread.hppfor some reason. I don't know how it knows about
thread_manager`。
解决这个问题的一种方法是将线程管理器作为模板参数注入:
// 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
。在这种情况下,您可以创建一个提供与 thread_manager
相同界面但不执行任何操作的虚拟 ThreadManager
,并将此 class 设置为默认模板参数。
#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(); }
} ;
另一种变体:在模板中保留 somefunction 的声明 并在单独的文件中实现它。