如何在C ++中声明/定义相互依赖的模板?

时间:2017-07-30 17:52:18

标签: c++ templates compilation include c-preprocessor

通常在C ++中,当我需要类之间的相互依赖关系时,我在头文件中使用前向声明,然后在每个cpp文件中包含两个头文件。

但是,在使用模板时,这种方法会中断。因为模板必须完全在头文件中(不包括我将代码放入cpp并为每个支持的template class A<T>;枚举T时的情况) - 这并不总是可行的,例如当{{1}时是一个lambda)。

那么有没有办法在C ++中声明/定义相互依赖的模板?

代码示例

T

如果我开始对template<typename T> struct B; template<typename T> struct A { void RunA(B<T> *pB) { // need to do something to B here } }; template<typename T> struct B { void RunB(A<T> *pA) { // need to do something to A here } }; 中的B做一些事情,我想,我会得到一个“缺少定义”的错误,因为在RunA()之前只有B的前向声明可用编译。

也许有一些技巧来组织头文件,例如通过将每个头分成类定义和方法定义文件,然后以一些奇特的方式包含它们。或者可以通过第三/第四课来完成某些事情。但我无法想象这样做有多具体。

C ++ 11/14/17还可以(具体来说,它是MSVC ++ 2017,工具集v141)。

2 个答案:

答案 0 :(得分:1)

您可以使用细粒度标题:

//  A.forward.hpp
template<typename T> struct A;

//  A.decl.hpp
#include "A.forward.hpp"
#include "B.forward.hpp"

template<typename T> struct A
{
    void RunA(B<T> *pB);
};

//  A.impl.hpp
#include "A.decl.hpp"
#include "B.hpp"

template<typename T> void A< T >::
RunA(B<T> *pB)
{
    // need to do something to B here
}

//  A.hpp // this one should be included by code using A
#include "A.decl.hpp"
#include "A.impl.hpp"

//  B.forward.hpp
template<typename T> struct B;

//  B.decl.hpp
#include "B.forward.hpp"
#include "A.forward.hpp"

template<typename T> struct B
{
    void RunB(A<T> *pA);
};

//  B.impl.hpp
#include "B.decl.hpp"
#include "A.hpp"

template<typename T> void B< T >::
RunB(A<T> *pA)
{
    // need to do something to A here
}

//  B.hpp // this one should be included by code using B
#include "B.decl.hpp"
#include "B.impl.hpp"

显然所有这些标题还需要某种我在这里省略的标题保护。 重要提示.impl.hpp标题被视为内部标题,永远不应被外部代码使用,.forward.hpp.decl.hpp.hpp可在任何地方使用

这种方法确实引入了循环包含依赖项,但这不会导致问题:通过包含头文件生成的代码结构可确保代码部分按以下顺序包含:前向声明,类定义,方法定义。

答案 1 :(得分:0)

您可以分隔类的声明和定义。因此,您可以分离模板类的声明和定义......

您可以分离类方法的声明和定义。因此,您可以分离模板类方法的声明和定义:

template<typename T> struct B;     // declaration

template<typename T> struct A {     // definition
  void RunA(B<T> *pB);  // declaration
};

template<typename T> struct B {     // definition
  void RunB(A<T> *pA);   // declaration
};

// definition
template<typename T>
void A<T>::RunA(B<T> *pB) {
    // need to do something to B here
  }

// definition    
template<typename T>
void B<T>::RunB(A<T> *pA) {
    // need to do something to A here
  }