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

How to declare/define interdependent templates in C++?

本文关键字:依赖 定义 C++ 声明      更新时间:2023-10-16

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

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

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

代码示例

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
}
};

如果我开始做一些事情来BRunA(),我想,我会得到一个"缺少定义"错误,因为在编译时只有 B 的前向声明可用RunA()

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

C++11/14/17 没问题(具体来说,它是 MSVC++2017,工具集 v141(。

您可以使用细粒度标头:

//  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可以在任何地方使用。

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

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

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

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
}