我有这三个文件
// foo.h
#pragma once
template <typename T> const T foo;
template <>
const int foo<int> = 1;
// a.cpp
#include "foo.h"
int main() {}
// b.cpp
#include "foo.h"
如果我在 Linux 上使用 GCC 7.5.0 构建它们,它工作正常:
$ g++ -std=c++17 a.cpp b.cpp -o out
$
但是在 Mac 上使用 Apple Clang 12.0.0 时会出现此错误:
$ clang++ -std=c++17 a.cpp b.cpp -o out
duplicate symbol 'foo<int>' in:
/var/folders/g5/8twmk1xj481_6btvppyw5j4h0000gp/T/a-62bdde.o
/var/folders/g5/8twmk1xj481_6btvppyw5j4h0000gp/T/b-ea4997.o
ld: 1 duplicate symbol for architecture x86_64
这应该是错误,还是 Clang 中的错误?
最佳答案
RedFrog 的回答是正确的 - 这违反了单一定义规则 (ODR),但它并没有真正解释为什么它违反了 ODR。在 C++ 中,全局 const
变量具有内部 (static
) 链接,这会导致每个编译单元都有一个单独的变量实例,因此不会违反 ODR。然而it turns out const
不会导致 template 变量具有内部链接:
The const qualifier used on a declaration of a non-local non-volatile non-template (since C++14) non-inline (since C++17) variable that is not declared extern gives it internal linkage.
有几种方法可以解决这个问题。
内部链接使用static
您可以在模板变量上使用 static
到 gives them internal linkage :
Any of the following names declared at namespace scope have internal linkage:
variables, variable templates (since C++14), functions, or function templates declared static;
编辑:我不推荐使用这种技术。如果您将 static
应用于声明和特化,那么它在 Clang 中工作正常,但 GCC(至少现在)提示
error: explicit template specialization cannot have a storage class
如果您仅在声明中设置 static
,那么它会在 GCC 中编译,但您会在 Clang 中遇到重复符号错误。
使用命名空间
的内部链接
将模板变量放在匿名命名空间中也会为它们提供内部链接。
In addition, all names declared in unnamed namespace or a namespace within an unnamed namespace, even ones explicitly declared extern, have internal linkage.
使用内联
禁用ODR
这有点不同。声明为 inline
但不是 static
的模板变量仍然具有外部链接,但是 are allowed to have more than one definition .
An inline function or variable (since C++17) with external linkage (e.g. not declared static) has the following additional properties:
- There may be more than one definition of an inline function or variable (since C++17) in the program as long as each definition appears in a different translation unit and (for non-static inline functions and variables (since C++17)) all definitions are identical. For example, an inline function or an inline variable (since C++17) may be defined in a header file that is #include'd in multiple source files.
- It must be declared inline in every translation unit.
- It has the same address in every translation unit.
这意味着变量的 inline
行为类似于函数的 inline
。
如果有疑问,inline
可能是最好的选择。在我做过的非常简单的测试中,它们都产生了相同的输出,即使是 -O0,但理论上 inline
保证你的程序中只有一个变量拷贝,因为它仍然有外部链接,而其他方法则没有。也许吧。
关于c++ - 使用 Clang 复制具有全局模板变量的符号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64610024/