内联模板专业化

时间:2018-08-23 13:50:44

标签: c++ inline template-specialization one-definition-rule template-function

如果我的头文件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,为什么要进行专业化处理?

2 个答案:

答案 0 :(得分:5)

显式专业化不是隐式内联的。必须将其显式内联。

  

[temp.expl.spec]/12

     

函数或变量模板的显式专业化是   仅当用内联说明符声明或定义为   删除,并且与它的功能或变量无关   模板是内联的。 [示例:

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 专门化是事实上模板,因为在编译过程中仍需要执行其实现。因此,部分模板专长享受从模板继承的豁免,而显式/全部专长则没有。