RedFrog 的答案是正确的 - 这违反了单一定义规则(ODR),但它并没有真正解释why它违反了 ODR。在 C++ 全局中const
变量有内部(static
) 链接,这应该为每个编译单元生成一个单独的变量实例,因此不会违反 ODR。然而事实证明 that const
不会导致template具有内部链接的变量:
在未声明为 extern 的非本地非易失性非模板 (C++14 起) 非内联 (C++17 起) 变量的声明上使用的 const 限定符赋予其内部链接。
有几种方法可以解决这个问题。
内部链接使用static
您可以使用static
在模板变量上给他们内部联系:
在命名空间范围内声明的以下任何名称都具有内部链接:
声明为静态的变量、变量模板 (C++14 起)、函数或函数模板;
编辑:我不建议使用这种技术。如果您申请static
对于声明和专业化,那么它在 Clang 中工作得很好,但 GCC(至少到目前为止)抱怨说
error: explicit template specialization cannot have a storage class
如果你设置static
仅在声明上,然后它在 GCC 中编译,但使用 Clang 时会出现重复的符号错误。
内部链接使用namespace
将模板变量放在匿名名称空间中还可以为它们提供内部链接。
此外,在未命名命名空间或未命名命名空间内的命名空间中声明的所有名称,即使是显式声明为 extern 的名称,也具有内部链接。
使用禁用 ODRinline
这有点不同。声明的模板变量inline
但不是static
仍然有外部链接,但是允许有多个定义.
具有外部链接(例如未声明为静态)的内联函数或变量 (C++17 起) 具有以下附加属性:
- 程序中可能存在多个内联函数或变量 (C++17 起) 的定义,只要每个定义出现在不同的翻译单元中并且(对于非静态内联函数和变量 (C++17 起) )) 所有定义都是相同的。例如,内联函数或内联变量 (C++17 起) 可以在多个源文件中 #include 的头文件中定义。
- 它必须在每个翻译单元中声明为内联。
- 它在每个翻译单元中具有相同的地址。
这意味着inline
对于变量的行为就像inline
对于功能。
如有疑问,inline
可能是最好的选择。在我所做的非常简单的测试中,它们都产生相同的输出,即使在 -O0 时也是如此,但理论上inline
保证程序中只有该变量的一个副本,因为它仍然具有外部链接,而其他方法则没有。或许。