为什么模板专业化需要内联?

Why do templates specialisations need to be inlined?

本文关键字:专业化 为什么      更新时间:2023-10-16

我指的是这个答案:

https://stackoverflow.com/a/4447057/930315

我遇到了与所引用问题的OP类似的问题, 具有函数

template<typename T>
void func(T& val);

及其专业化

template<>
void func<mytype>(mytype& val);

导致重复符号链接器错误(这些方法在我的标头末尾包含的".tpp"文件中实现)。 向专用功能添加inline解决了该问题。为什么?

好吧,如果你想要这方面的标准报价,那就在 [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 

— 结束示例 ]

这就是为什么你必须这样做。它是独立的,因为我相信否则会受到不必要的限制,正如 Yola 所证明的那样。

这将在没有内联的情况下工作:

文件1.h

template<typename T> void func(T& val);
template<> void func<mytype>(mytype& val);

文件1.cpp

template<> void func<int>(int& ) {}

但是,如果您在头文件中定义模板专用化,则可能会违反ODR

根据 c++ 标准中的条款 3.2:4

每个

程序应只包含每个非内联的一个定义 该程序中使用的 ODR 函数或变量;无诊断 必填。定义可以显式出现在程序中,它可以 在标准或用户定义的库中找到,或者(当 适当)它是隐式定义的(见 12.1、12.4 和 12.8). 内联函数应在使用它的每个翻译单元中定义。

这就解释了为什么当专用函数未内联声明时会出现链接时错误。该程序将包含专用函数的多个定义,每个模块(包括.tpp文件)一个定义,这打破了标准中的条件。当声明专用函数inline时,它将使函数满足同一子句的第二部分,即必须在使用该函数在每个模块中定义一个内联函数。

当参数化函数不是专用的时,它包含在条款 3.2:6 中:

类类型可以有多个定义(第 9 条), 枚举类型 (7.2)、带外部链接的内联函数 (7.1.2), 类模板(条款 14)、非静态函数模板 (14.5.6)、 类模板的静态数据成员 (14.5.1.3),成员函数 类模板 (14.5.1.1),或模板专用化,其中一些 程序中未指定模板参数(14.7、14.5.5) 前提是每个定义出现在不同的翻译单元中

此子句指出,只要代码中未指定至少一个模板参数,就可以对同一模板函数进行多个定义。这是为了允许仅根据本地信息决定是否应在模块中实例化参数化函数。