说我的代码以这种方式构建:
那么header1.h
template <class T, template<class> class C>
struct metafunction {
using type = typename C<T>::type;
};
inline namespace msn {
template <class T> struct implementation;
}
// uses the *implementation* not defined in the header!
template <class T>
struct use_case {
using type = typename metafunction<T, implementation>::type;
};
cpp1.cpp
#include <header1.h>
// I'll only need this in this compilation unit, so the
// question is: "Is this a good place to define it?"
template <>
struct implementation<int> {
using type = int;
};
int main() {
using tt = int;
// is this point of instantiation OK due to
// the existence of a specialization in the same cpp file?
using tt = use_case<int>::type;
tt var;
(void)var;
}
我的前提条件是我只会在cpp文件中使用特定的特化,所以我不必处理链接器问题。 我知道这不适用于cpp2.cpp
文件,包括header1.h
并尝试仅使用use_case<int>
或重新定义违反ODR的implementation<int>
。所以我要问的是这个代码是否类似于它的linear form(一个版本,其中所有东西都被放入一个符合顺序的单个cpp文件中)(显然)编译得很好。
答案 0 :(得分:8)
是的,只要在同一个翻译单元中使用它,这就是格式良好的。
请记住,#include
的效果是 - 如果引用的文件逐字插入翻译单元。
这就是#include
。
由此,我们可以得出几个结论:
每个C ++翻译单元都是一个虚拟文件。
因此,格式良好的翻译单元中的每个专业化都在定义它的同一翻译单元中引用。
Q.E.D。
答案 1 :(得分:0)
一般来说,我同意@Sam的回答,但我会仅针对本地类型进行此类专业化。使用&#34;本地类型&#34;我的意思是只能在这个翻译单元中访问的类型,例如仅在此.cpp文件中定义的类(在匿名命名空间中)。
原因在于,当以这种方式对可广泛访问的类型进行专门化,比专业化更广泛时,很容易出现ODR(一个定义规则)违规。如果将来另一个代码开始使用相同类型的模板时,很容易理解你得到的模板的两个实例是不相同的(一个是专业化而一个没有它) 。在这种情况下,这是ODR违规,并且没有定义行为。
所以int
它绝对不是一个很好的候选人#34; local&#34;专业化。
如果您仍希望在.cpp文件中本地具有专门化,可能您想要在模板参数中添加其他标记(这也需要在原始模板中添加另一个参数),并且此标记将包含本地类型(例如,在此文件中的匿名命名空间内定义struct private_tag{};
并在专门化中使用它)。这样,专业化具有一种不能在任何其他TU中使用的独特类型,因此您可以免受ODR违规。