c++ - 使用 Clang 复制具有全局模板变量的符号

标签 c++ templates clang compiler-bug

我有这三个文件

// 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

您可以在模板变量上使用 staticgives 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/

相关文章:

c++ - 在 Opengl 中画一条线不显示 C++

c++ - 使用单参数模板化构造函数从引用元组构造值元组

c++ - 在 Windows 上使用 WaitForSingleObject 但支持 boost 线程中断

c++ - MFC如何从另一个类获取CString到CRegSettings类

c++ - friend 模板特化声明中不允许使用 Consexpr?

C++::成员函数数组

XCode6:接收错误 "Include of non-modular header inside framework module"

ios - 如何在运行时访问类的源代码级定义?

ios - 在 xcode 中设置 C 编译标志

c++ - 仍然无法将 WDK 8 集成到 VisualC++ 2012 速成版中?