如何在 C++ 中声明/定义相互依赖的模板?
通常在 C++ 中,当我需要类之间的相互依赖时,我在头文件中使用前向声明,然后在每个 cpp 文件中包含两个头文件.
Usually in C++ when I need interdependencies between classes, I use forward declarations in the header files and then include both header files in each cpp file.
然而,这种方法在使用模板时会中断.因为模板必须完全在头文件中(不包括将代码放入 cpp 并为每个支持的 T
枚举 template class A<T>
的情况 -这并不总是可行的,例如当 T
是一个 lambda 时).
However this approach breaks when working with templates. Because templates have to be entirely in the header files (not counting the case when I put the code into cpp and enumerate template class A<T>;
for each supported T
- this is not always feasible, e.g. when T
is a lambda).
那么有没有办法在 C++ 中声明/定义相互依赖的模板?
So is there a way to declare/define interdependent templates in 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
}
};
如果我开始对 RunA()
中的 B
做一些事情,我想,我会得到一个缺少定义"的错误,因为只有 B 的前向声明是可用的RunA()
编译的时间.
If I start doing something to B
in RunA()
, I think, I will get a "missing definition" error because only forward declaration of B is available by the time RunA()
is compiled.
也许有一些技巧可以组织头文件,例如通过将每个头文件拆分为类定义和方法定义文件,然后以某种奇特的方式包含它们.或者也许可以通过第三/第四类完成某些事情.但我无法想象具体如何做到这一点.
Perhaps there is some trick to organize header files e.g. by splitting each header into class definition and method definition files, and then including them in some fancy way. Or maybe something can be done via a third/fourth class. But I can't imagine how specifically to do this.
C++11/14/17 没问题(具体来说,它是 MSVC++2017,工具集 v141).
C++11/14/17 are ok (specifically, it's MSVC++2017, toolset v141).
推荐答案
您可以使用细粒度的标题:
You can utilize fine-grained headers:
// 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
可以在任何地方使用.
Obviously all of these headers also need some sort of header guards that I omitted here. Important notice: .impl.hpp
headers are considered internal and should never be used by the outside code while .forward.hpp
, .decl.hpp
and .hpp
can be used anywhere.
这种方法确实引入了循环包含依赖,但这不会导致问题:包含头文件产生的代码结构确保代码部分按以下顺序包含:前向声明、类定义、方法定义.
This approach does introduce circular include dependencies, however this does not lead to problems: code structure produced by inclusion of headers ensures that code parts are included in the following order: forward declarations, class definitions, methods definitions.
相关文章