【发布时间】:2018-01-06 06:14:24
【问题描述】:
通常在 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
}
};
如果我开始在RunA() 中对B 做某事,我想我会收到“缺少定义”错误,因为在编译RunA() 时只有B 的前向声明可用。
也许有一些技巧来组织头文件,例如通过将每个标头拆分为类定义和方法定义文件,然后以某种奇特的方式包含它们。或者也许可以通过第三/第四类来完成某些事情。但我无法想象如何具体做到这一点。
C++11/14/17 还可以(具体来说,它是 MSVC++2017,工具集 v141)。
【问题讨论】:
-
不要列出编译器的年份,而是列出版本,因为VS15可以安装3个不同的编译器版本(之前的都只有一个)。
-
@SergeyB.,这解决了我给出的代码示例的特定问题。但是,我想要一个一般准则,例如“而不是使用 .h 和 .cpp 文件,您需要第三种类型的文件,例如 .inl ,它将包含函数定义”,然后解释如何管理包含。 ...
-
也许您可以将成员方法设为函数模板并通过
static_assert强制类型,例如:template<template<typename> class C> void RunA(C<T> *pB { static_assert(std::is_same<C<T>, B<T>>::value, "!"); // ... }。这样,您只需要在调用点定义B。它对你有用吗? -
@skypjack ,我更喜欢简单且可扩展的解决方案,例如 VTT 提出的单独标头。虽然我怀疑这是否是最简单的解决方案...... 4个标题似乎太多了。
-
@SergeRogatch 好吧,当第三个班级进入循环时,您可能已经回顾了您对 scalable 一词的含义。 :-)
标签: c++ templates compilation include c-preprocessor