如果我的头文件foo.h包含在我的整个项目中,那么当它包含的所有内容都是:
template<typename T>
void foo(const T param) {
cout << param << endl;
}
但是当我在foo.h中添加规范化时,会出现一个定义规则(ODR)错误:
template<>
void foo(const bool param) {
cout << param << endl;
}
很明显,我可以通过inline
进行专业化解决。我的问题是,为什么我需要这样做?如果模板没有违反ODR,为什么要进行专业化处理?
答案 0 :(得分:5)
显式专业化不是隐式内联的。必须将其显式内联。
函数或变量模板的显式专业化是 仅当用内联说明符声明或定义为 删除,并且与它的功能或变量无关 模板是内联的。 [示例:
template<class T> void f(T) { /* ... */ } template<class T> inline T g(T) { /* ... */ } template<> inline void f<>(int) { /* ... */ } // OK: inline template<> int g<>(int) { /* ... */ } // OK: not inline
-示例]
所以您必须这样做,因为标准规定您必须这样做。
答案 1 :(得分:1)
免除ODR模板的原因仅仅是没有其他选择。
从编译器的角度来看,模板不是“有形的最终产品”。模板的实现必须随身携带,以便在使用时可以扩展为可编译代码。结果,它必须驻留在头文件中,因此来自不同编译单元的重复定义是不可避免的。由于这是不可避免的,因此该标准做出了让步,以使其免除ODR。
一个函数是一个最终产品,可以很容易地编译成目标代码,因此即使完全有可能比较代码并在代码相同的情况下继续操作,编译器也不愿看到潜在的冲突定义。但是,编译器认为他们太懒了以至于无法进行此类额外检查,因此该标准禁止使用多个定义。
现在,模板功能的显式/完全专业化是事实上一个功能,而不是模板-因为所有缺失的部分都已填充,并且没有需要再携带专门功能的定义。相反, partial 专门化是事实上模板,因为在编译过程中仍需要执行其实现。因此,部分模板专长享受从模板继承的豁免,而显式/全部专长则没有。