由于标头中的专业化初始化而避免重复的符号?

jww*_*jww 1 c++ templates initialization static-members template-specialization

由于我试图在标题中提供的定义,我正在捕获重复的符号错误.这是Minimal,Complete和Verifiable示例中的错误.头文件和源文件如下所示.

$ clang++ main.cpp x.cpp y.cpp -o main.exe 2>&1 | c++filt
duplicate symbol Id<S>::id in:
    /tmp/main-3f2415.o
    /tmp/long long-d62c28.o
duplicate symbol Id<T>::id in:
    /tmp/main-3f2415.o
    /tmp/long long-d62c28.o
duplicate symbol Id<S>::id in:
    /tmp/main-3f2415.o
    /tmp/unsigned long long-bfa6de.o
duplicate symbol Id<T>::id in:
    /tmp/main-3f2415.o
    /tmp/unsigned long long-bfa6de.o
ld: 4 duplicate symbols for architecture x86_64
Run Code Online (Sandbox Code Playgroud)

这是一个类似的问题,但它不涉及专门化:类模板中的静态成员初始化.这个问题有专门化,但它适用于MSVC而不是Clang:如何初始化参数化模板类的静态成员.并且这个问题表明它将它放在源(*.cpp)文件中,但我们的目标是避免使用头文件Clang 3.8和'Id<S>::id' required here, but no definition is available警告:类模板的显式特化的定义应放在C++中的哪个位置?

初始化时,GCC,ICC,MSVC,SunCC和XLC都可以.Clang和LLVM给了我麻烦.Clang和LLVM在专门化的明确实例化方面也遇到了麻烦extern,因此它拥有特殊的地狱.

我们支持C++ 03但是C++ 17,所以我们必须小心这个解决方案.天真地,我尝试将特化的初始化放在一个未命名的命名空间中,以防止符号转义转换单元,但这导致了编译错误.

在标头中初始化和专门化模板类时,我们如何避免重复的符号定义?


下面是MCVE,它是一个cat main.cpp a.h s.h s.cpp t.h t.cpp x.cpp y.cpp.问题似乎在于a.h,它提供了专业化和初始化; 和源文件x.cppy.cpp,其中包括a.h.

main.cpp中

#include "a.h"
#include "s.h"
#include "t.h"

int main(int argc, char* argv[])
{
    uint8_t s = Id<S>::id;
    uint8_t t = Id<T>::id;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

#ifndef A_INCLUDED
#define A_INCLUDED

#include <stdint.h>

template <class T> class Id
{
public:
    static const uint8_t id;
};

class S;
class T;

template<> const uint8_t Id<S>::id = 0x01;
template<> const uint8_t Id<T>::id = 0x02;

#endif
Run Code Online (Sandbox Code Playgroud)

SH

#ifndef S_INCLUDED
#define S_INCLUDED

class S {
public:
    S();
};

#endif
Run Code Online (Sandbox Code Playgroud)

s.cpp

#include "s.h"

S::S() {}
Run Code Online (Sandbox Code Playgroud)

#ifndef T_INCLUDED
#define T_INCLUDED

class T {
public:
    T();
};

#endif
Run Code Online (Sandbox Code Playgroud)

t.cpp

#include "t.h"

T::T() {}
Run Code Online (Sandbox Code Playgroud)

x.cpp

#include "a.h"
Run Code Online (Sandbox Code Playgroud)

y.cpp的

#include "a.h"
Run Code Online (Sandbox Code Playgroud)

小智 6

Clang/LLVM不是问题.您只是在没有诊断要求的情况下遇到未定义的行为.修复很简单.您需要将您的专业化设置在一个翻译单元中.即

a.cpp:

#include "a.h"

template<> const uint8_t Id<S>::id = 0x01;
template<> const uint8_t Id<T>::id = 0x02;
Run Code Online (Sandbox Code Playgroud)

然后是命令行:

clang++ main.cpp a.cpp x.cpp y.cpp -o main.exe 2>&1 | c++filt
Run Code Online (Sandbox Code Playgroud)

瞧.有用.