如何在C+中声明/定义相互依赖的模板+;? 通常在C++中,当类之间需要相互依赖时,我在头文件中使用前向声明,然后在每个CPP文件中包含头文件。
但是,使用模板时,此方法会中断。因为模板必须完全位于头文件中(不包括我将代码放入cpp并为每个受支持的如何在C+中声明/定义相互依赖的模板+;? 通常在C++中,当类之间需要相互依赖时,我在头文件中使用前向声明,然后在每个CPP文件中包含头文件。,c++,templates,compilation,include,c-preprocessor,C++,Templates,Compilation,Include,C Preprocessor,但是,使用模板时,此方法会中断。因为模板必须完全位于头文件中(不包括我将代码放入cpp并为每个受支持的T枚举模板类A;时的情况-这并不总是可行的,例如当T是lambda时) a.impl.hpp->B.hpp->B.impl.hpp->a。hpp@SergeRogatch是的,但是A.hpp不会第二次包括在内,这不会造成问题。如果您只包含A.hpp、B.hpp或以任何顺序包含这两个选项,那么它都可以正常工作。你应该自己试试。显然,所有这些头文件都需要一些我在这里忽略的头文件保护。重要提示:.de
T
枚举模板类A;
时的情况-这并不总是可行的,例如当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
}
};
模板结构B;
模板结构A{
无效RunA(B*pB){
//这里需要做点什么
}
};
模板结构B{
无效运行B(A*pA){
//我需要做点什么来帮助你
}
};
如果我开始在RunA()
中对B
执行操作,我想,我会得到一个“缺少定义”错误,因为在编译RunA()
时,只有B的前向声明可用
也许有一些技巧可以组织头文件,例如将每个头文件拆分为类定义文件和方法定义文件,然后以某种奇特的方式包含它们。或者可以通过第三/第四节课做些什么。但我无法想象具体怎么做
C++11/14/17还可以(特别是MSVC++2017,工具集v141)。您可以将类的声明和定义分开。因此,您可以分离模板类的声明和定义
您可以分离类方法的声明和定义。因此,您可以分离模板类方法的声明和定义:
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
}
模板结构B;//宣言
模板结构A{//定义
void RunA(B*pB);//声明
};
模板结构B{//定义
void RunB(A*pA);//声明
};
//定义
模板
void A::RunA(B*pB){
//这里需要做点什么
}
//定义
模板
void B::RunB(A*pA){
//我需要做点什么来帮助你
}
您可以利用细粒度头:
// 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"
//A.forward.hpp
模板结构A;
//A.decl.hpp
#包括“A.forward.hpp”
#包括“B.forward.hpp”
模板结构A
{
无效RunA(B*pB);
};
//A.impl.hpp
#包括“A.decl.hpp”
#包括“B.hpp”
模板无效A::
RunA(B*pB)
{
//这里需要做点什么
}
//A.hpp//这一个应该通过使用
#包括“A.decl.hpp”
#包括“A.impl.hpp”
//B.forward.hpp
模板结构B;
//B.decl.hpp
#包括“B.forward.hpp”
#包括“A.forward.hpp”
模板结构B
{
无效RunB(A*pA);
};
//B.impl.hpp
#包括“B.decl.hpp”
#包括“A.hpp”
模板无效B::
RunB(A*pA)
{
//我需要做点什么来帮助你
}
//B.hpp//这一个应该包含在使用B的代码中
#包括“B.decl.hpp”
#包括“B.impl.hpp”
显然,所有这些头文件都需要一些我在这里忽略的头文件保护。重要提示:.impl.hpp
标题被视为内部标题,当.forward.hpp
、.decl.hpp
和可以在任何地方使用时,外部代码都不能使用
这种方法确实引入了循环包含依赖项,但这不会导致问题:通过包含头生成的代码结构确保代码部分按以下顺序包含:正向声明、类定义、方法定义。请列出版本,而不是列出编译器的年份,由于VS15能够安装3个不同的编译器版本(以前的所有版本都只有一个)。@SergeyB.,这就解决了我给出的代码示例的特定问题。但是,我想要一个一般性的指导原则,比如“不要有一个.h和一个.cpp文件,而要有模板,你需要第三种类型的文件,比如.inl,它将包含函数定义”然后,对如何管理的解释包括……可能您可以将成员方法设置为函数模板,并通过static\u assert
强制该类型,例如:template void RunA(C*pB{static\u assert(std::is\u same::value,“!”;/…}
。这样,你只需要在呼叫点定义B
。它对你有用吗?@skypjack,我更喜欢VTT提出的一个简单且可扩展的解决方案,如单独的标题。尽管我怀疑这是否是最简单的解决方案……4个标题似乎太多了。@SergeRogatch好吧,到第三个类将被使用时r在这个循环中,您可能已经回顾了您对“可伸缩性”一词的含义。:-)这很清楚。但实际上,将所有内容都放在一个文件中很不方便。问题是如何将这些声明/定义拆分为头文件,以及如何包含它们。@SergeRogatch与.hpp和.cpp的方法相同。通常使用扩展名.ipp作为模板函数定义。ipp?有趣的是,在15年的实践中从未看到过。。。通常是.inc,有时是.impl。。。但是我喜欢它。在这个设计中有一个循环包含:a.hpp->a.impl.hpp->B.hpp->B.impl.hpp->a。hpp@SergeRogatch是的,但是A.hpp不会第二次包括在内,这不会造成问题。如果您只包含A.hpp、B.hpp或以任何顺序包含这两个选项,那么它都可以正常工作。你应该自己试试。显然,所有这些头文件都需要一些我在这里忽略的头文件保护。重要提示:.decl.hpp和.impl.hpp头被认为是内部的,外部代码不应该使用它们,而.forward.hpp和.hpp可以在任何地方使用。这值得在您的答案中描述。此外,这是标准/最佳实践吗?还是你刚刚想出了这个解决方案?我想知道有更好的解决方案的可能性有多大…@SergeRogatch好吧,至少在过去五年里,我一直在实践这种方法。而且效果非常好。通常我