xsk*_*xzr 9 c++ standards templates one-definition-rule language-lawyer
对于给定的模板和给定的模板参数集,
...
在程序中最多只能定义一次显式特化(根据[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>是一个不完整的类型.
总之,我应该在哪里放置类模板的显式特化的定义?
我将尝试在这里总结我通过其他答案中的讨论所学到的知识,希望为这个问题留下一个好的答案,而不是将答案埋在评论中。
标准说
显式专业化最多应在程序中定义一次(根据 ODR)
ODR 是单一定义规则。您只能在程序中定义每个类一次,但有一个例外,即允许类定义在每个翻译单元中可用:您可以在不同的翻译单元中定义类,只要这些不同的定义逐个字符相同即可。OP 的引用是 ODR 描述的一部分,请点击OP 的链接查看完整的描述。
因此,IMO 上面的标准文本意味着显式专业化只能定义一次,但根据 ODR,因此有相同的例外:您可以在头文件中定义它,以便它在多个翻译单元中可用。
请注意,如果没有完整的定义,则无法实例化类(编译器至少需要知道要为其分配多少字节)。对于模板类或此类类的特化也是如此。因此,该定义必须有可能出现在使用它的每个翻译单元中。