模板循环依赖 - 在不同的文件中分开 类

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 的定义之后包含内联函数(包括模板成员和模板函数)所需的定义。这样我就不用担心是否有必要这样做了。