应该在C++中将类模板的显式特化的定义放在何处?

xsk*_*xzr 9 c++ standards templates one-definition-rule language-lawyer

根据[temp.spec]/5:

对于给定的模板和给定的模板参数集,

  • ...

  • 在程序中最多只能定义一次显式特化(根据[basic.def.odr]),和

  • ...

类模板的显式(完整)特化的定义不能放在标题中(否则每个包含此标题的翻译单元中都有一个定义,因此整个程序中将有多个定义).

此外,作为另一个证据,[basic.def.odr]/12(下面的块引用)中列出的实体不包含类模板的完全特化.而是包含" 未指定某些模板参数的模板特化 ".

可以有多个类类型的定义,枚举类型,带外部链接的内联函数([dcl.inline]),带外部链接的内联变量([dcl.inline]),类模板,非静态函数模板, concept([temp.concept]),类模板的静态数据成员,类模板的成员函数,或未指定某些模板参数的模板特化([temp.spec],[temp.class.spec])在程序中,每个定义出现在不同的翻译单元中,并且定义满足以下要求.

但是,如果我将定义放在源文件中并将其声明保留在标题中,例如,

// "a.h"
template <typename T>
struct S {};

template <>
struct S<int>; // declaration

// "a.cpp"
#include "a.h"

template <>
struct S<int> {}; // definition

// "main.cpp"
#include "a.h"

int main()
{
    S<int> s;
}
Run Code Online (Sandbox Code Playgroud)

然后发生错误(由gcc测试),因为它S<int>是一个不完整的类型.

总之,我应该在哪里放置类模板的显式特化的定义?

Cri*_*ngo 2

我将尝试在这里总结我通过其他答案中的讨论所学到的知识,希望为这个问题留下一个好的答案,而不是将答案埋在评论中。

标准说

显式专业化最多应在程序中定义一次(根据 ODR)

ODR 是单一定义规则。您只能在程序中定义每个类一次,但有一个例外,即允许类定义在每个翻译单元中可用:您可以在不同的翻译单元中定义类,只要这些不同的定义逐个字符相同即可。OP 的引用是 ODR 描述的一部分,请点击OP 的链接查看完整的描述。

因此,IMO 上面的标准文本意味着显式专业化只能定义一次,但根据 ODR,因此有相同的例外:您可以在头文件中定义它,以便它在多个翻译单元中可用。

请注意,如果没有完整的定义,则无法实例化类(编译器至少需要知道要为其分配多少字节)。对于模板类或此类类的特化也是如此。因此,该定义必须有可能出现在使用它的每个翻译单元中。