Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在C+中声明/定义相互依赖的模板+;? 通常在C++中,当类之间需要相互依赖时,我在头文件中使用前向声明,然后在每个CPP文件中包含头文件。_C++_Templates_Compilation_Include_C Preprocessor - Fatal编程技术网

如何在C+中声明/定义相互依赖的模板+;? 通常在C++中,当类之间需要相互依赖时,我在头文件中使用前向声明,然后在每个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

但是,使用模板时,此方法会中断。因为模板必须完全位于头文件中(不包括我将代码放入cpp并为每个受支持的
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好吧,至少在过去五年里,我一直在实践这种方法。而且效果非常好。通常我