c++ - 在 C++ 中,类模板的显式特化定义应该放在哪里?

标签 c++ templates language-lawyer standards one-definition-rule

根据 [temp.spec]/5 :

For a given template and a given set of template-arguments,

  • ...

  • an explicit specialization shall be defined at most once in a program (according to [basic.def.odr]), and

  • ...

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

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

There can be more than one definition of a class type, enumeration type, inline function with external linkage ([dcl.inline]), inline variable with external linkage ([dcl.inline]), class template, non-static function template, concept ([temp.concept]), static data member of a class template, member function of a class template, or template specialization for which some template parameters are not specified ([temp.spec], [temp.class.spec]) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements.

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

// "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;
}

然后发生错误 ( tested by gcc ) 因为 S<int>是一个不完整的类型。

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

最佳答案

我将尝试在这里总结我通过 the discussion in my other answer 学到的知识,希望为这个问题留下一个好的答案,而不是让答案埋在评论中。

标准说

an explicit specialization shall be defined at most once in a program (according to ODR)

ODR 是单一定义规则。您只能在程序中定义每个类一次,但设计允许类定义在每个翻译单元中可用的异常(exception)情况:您可以在不同的翻译单元中定义一个类,只要这些不同的定义是相同的,一个字符一个字符。 OP的引用是ODR描述的一部分,关注the OP's link查看完整说明。

因此 IMO 标准的上述文本意味着显式特化只能定义一次,但根据 ODR,因此有相同的异常(exception):您可以在头文件中定义它,以便它在多个翻译单元中可用。

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

关于c++ - 在 C++ 中,类模板的显式特化定义应该放在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47544299/

相关文章:

c++ - 将静态库链接到cmake中的共享库

c++11 - 为什么 constexpr 数据成员不是隐式静态的?

具有可寻址 GPR 文件、寄存器变量地址以及内存和寄存器之间的别名的 CPU

c++ - 如何为模板类编写复制构造函数 - C++

c - printf 长度修饰符 %L 是标准的(或 future 的标准)吗?

c++ - 嵌入式系统的开源视频编码器

c++ - 在构造基类期间访问继承的方法?

c++ - 指针如何将字符串作为其值?

C++11 简化了调用同一模板函数的不同特化的模板函数的语法

c++ - 如何将 `std::string` 传递给 `QString` `arg` 方法?