我有这三个文件

// 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中的错误?

最佳答案

它违反了ODR,应为inline(自C++ 17起)或未命名的namespace(自C++ 11起)。
为什么违反ODR:

因为foo.ha.cpp都包含b.cpp,所以在每个翻译单元foo<int>a.cpp中都定义了b.cpp变量。因此它在该程序中有2个定义,这违反了以前的规则,除非它是未使用的(意味着,不是ODR使用的)或它是inline变量。
您有2个解决方案:

  • template<> int const foo<int> = 1;放入另一个foo.cpp中。然后只有一个定义。
  • inline添加foo(从C++ 17开始)。一个inline变量允许翻译单元之间具有多个相同的定义。如果不是在C++ 17中,则可以将其放入未命名的namespace中,这意味着让其中的所有内容均为inline
  • 关于c++ - 使用Clang使用全局模板变量复制符号,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/64610024/

    10-11 23:06
    查看更多