内联模板专业化
Inlining Template Specialization
如果我有一个 header 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
'ing 专业化来解决这个问题。我的问题是,为什么我需要这样做?如果模板不违反 ODR,为什么要专门化?
显式特化不是隐式内联。它必须显式内联。
An explicit specialization of a function or variable template is
inline only if it is declared with the inline specifier or defined as
deleted, and independently of whether its function or variable
template is inline. [ Example:
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
— end example ]
所以你必须这样做,因为标准说你必须这样做。
模板免于ODR 的原因很简单,没有其他选择。
从编译器的角度来看,模板不是 "tangible end-product"。模板的实现必须随身携带,以便在使用时可以扩展为可编译代码。因此,它必须位于头文件中,来自不同编译单元的重复定义是不可避免的。既然不可避免,标准就做出妥协,免除ODR。
函数是可以很容易地编译成目标代码的最终产品,因此编译器不愿意看到可能存在冲突的定义,即使完全有可能比较代码并在代码相同时继续进行。然而,编译器决定他们懒得做这样的额外检查,因此标准禁止多重定义。
现在,模板函数的 explicit/full 特化 事实上 是一个函数,而不是模板 - 因为所有缺失的部分已被填补,不再需要携带专门功能的定义。相比之下,部分 特化是事实上 模板,因为它的实现仍然需要在编译期间进行。因此,部分模板特化享受从模板继承的豁免,而 explicit/full 特化则不然。
如果我有一个 header 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
'ing 专业化来解决这个问题。我的问题是,为什么我需要这样做?如果模板不违反 ODR,为什么要专门化?
显式特化不是隐式内联。它必须显式内联。
An explicit specialization of a function or variable template is inline only if it is declared with the inline specifier or defined as deleted, and independently of whether its function or variable template is inline. [ Example:
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
— end example ]
所以你必须这样做,因为标准说你必须这样做。
模板免于ODR 的原因很简单,没有其他选择。
从编译器的角度来看,模板不是 "tangible end-product"。模板的实现必须随身携带,以便在使用时可以扩展为可编译代码。因此,它必须位于头文件中,来自不同编译单元的重复定义是不可避免的。既然不可避免,标准就做出妥协,免除ODR。
函数是可以很容易地编译成目标代码的最终产品,因此编译器不愿意看到可能存在冲突的定义,即使完全有可能比较代码并在代码相同时继续进行。然而,编译器决定他们懒得做这样的额外检查,因此标准禁止多重定义。
现在,模板函数的 explicit/full 特化 事实上 是一个函数,而不是模板 - 因为所有缺失的部分已被填补,不再需要携带专门功能的定义。相比之下,部分 特化是事实上 模板,因为它的实现仍然需要在编译期间进行。因此,部分模板特化享受从模板继承的豁免,而 explicit/full 特化则不然。