模板循环依赖 - 在不同的文件中分开 类
Template circular dependency - seperate classes in different files
首先,我想说我知道以前有人问过这种问题(例如这里Resolving a Circular Dependency between Template Classes)。
但是,此解决方案(将声明与实现分开)仅在将两个 class 都放入一个文件时才有效。在我的例子中,我有一个 StateManager 和一个 State class,它们都相当大并且可以保证增长。因此,将它们放在一个大文件中对我来说似乎并不令人满意。
这里是一些重要的代码片段:
// Forward declare the StateManager --> does not work (incomplete type)
class State
{
public:
template <class TData>
void RequestStackPush(ID stateId, std::shared_ptr<TData> data);
private:
StateManager & stataManager;
}
这里是RequestStackPush()
方法的实现
template<class TData>
inline void State::RequestStackPush(ID stateId, std::shared_ptr<TData> data)
{
// Uses the state manager's PushState() method - here the issue with the incomplete type arises
stateManager.PushState<TData>(stateId, data);
}
显然,StateManager
一直使用 State
class。它创建它调用方法等。因此前向声明在这里不是解决方案。举个例子:
template<class TData>
inline void StateManager::PushState(State::ID stateId, std::shared_ptr<TData> data)
{
std::unique_ptr<BasePendingChange> pendingChange = std::make_unique<PendingPushDataChange<TData>>(Push, stateId, data);
pendingChangeQueue.push(std::move(pendingChange));
}
目前,两个 class 都在一个大文件中。首先,State
class 的声明和 StateManager
被向前声明,然后是 StateManager
class 的声明,然后是上述的实现State::RequestStackPush()
方法,最后执行所有 StateManager 模板方法。
如何将其分成两个不同的文件?
However, this solution (Separating the declaration from the implementation) only works when putting both classes into one file.
不,它不仅仅适用于一个文件。您始终可以通过包含 sub-headers 来构建相同的文件。它只需要你做一些在 non-templates 中不常见的事情(尽管同样的技术适用于所有内联函数定义):你需要在定义 class 之后包含一个文件。 Headers 不限于位于文件顶部,尽管给定了它们的名称。
因此,在一个文件中:
- 声明
StateManager
- 定义
State
- 包括
StateManager
的定义
- 定义依赖于
StateManager
定义的成员函数
其他文件没有异常:
- 包括
State
的定义
- 定义
StateManager
及其成员函数。
最终结果是,包含 header 中的任何一个都会按要求的顺序生成相同的定义和声明。因此,这种文件拆分绝不会有助于限制由修改 header 之一引起的 re-compilation 的数量。
这可能是个人喜好问题,但我总是在 class 的定义之后包含内联函数(包括模板成员和模板函数)所需的定义。这样我就不用担心是否有必要这样做了。
首先,我想说我知道以前有人问过这种问题(例如这里Resolving a Circular Dependency between Template Classes)。
但是,此解决方案(将声明与实现分开)仅在将两个 class 都放入一个文件时才有效。在我的例子中,我有一个 StateManager 和一个 State class,它们都相当大并且可以保证增长。因此,将它们放在一个大文件中对我来说似乎并不令人满意。
这里是一些重要的代码片段:
// Forward declare the StateManager --> does not work (incomplete type)
class State
{
public:
template <class TData>
void RequestStackPush(ID stateId, std::shared_ptr<TData> data);
private:
StateManager & stataManager;
}
这里是RequestStackPush()
方法的实现
template<class TData>
inline void State::RequestStackPush(ID stateId, std::shared_ptr<TData> data)
{
// Uses the state manager's PushState() method - here the issue with the incomplete type arises
stateManager.PushState<TData>(stateId, data);
}
显然,StateManager
一直使用 State
class。它创建它调用方法等。因此前向声明在这里不是解决方案。举个例子:
template<class TData>
inline void StateManager::PushState(State::ID stateId, std::shared_ptr<TData> data)
{
std::unique_ptr<BasePendingChange> pendingChange = std::make_unique<PendingPushDataChange<TData>>(Push, stateId, data);
pendingChangeQueue.push(std::move(pendingChange));
}
目前,两个 class 都在一个大文件中。首先,State
class 的声明和 StateManager
被向前声明,然后是 StateManager
class 的声明,然后是上述的实现State::RequestStackPush()
方法,最后执行所有 StateManager 模板方法。
如何将其分成两个不同的文件?
However, this solution (Separating the declaration from the implementation) only works when putting both classes into one file.
不,它不仅仅适用于一个文件。您始终可以通过包含 sub-headers 来构建相同的文件。它只需要你做一些在 non-templates 中不常见的事情(尽管同样的技术适用于所有内联函数定义):你需要在定义 class 之后包含一个文件。 Headers 不限于位于文件顶部,尽管给定了它们的名称。
因此,在一个文件中:
- 声明
StateManager
- 定义
State
- 包括
StateManager
的定义
- 定义依赖于
StateManager
定义的成员函数
其他文件没有异常:
- 包括
State
的定义
- 定义
StateManager
及其成员函数。
最终结果是,包含 header 中的任何一个都会按要求的顺序生成相同的定义和声明。因此,这种文件拆分绝不会有助于限制由修改 header 之一引起的 re-compilation 的数量。
这可能是个人喜好问题,但我总是在 class 的定义之后包含内联函数(包括模板成员和模板函数)所需的定义。这样我就不用担心是否有必要这样做了。