模板变量是否可以在多个翻译单元中使用并有效地合并?

时间:2018-10-03 15:00:54

标签: c++ templates

请参阅以下内容:

https://en.cppreference.com/w/cpp/language/definition#One_Definition_Rule

http://eel.is/c++draft/basic.def.odr#12

它声明了类模板的多个定义,类模板的静态数据成员,部分模板专门化等,并且将作为一个单独的定义。很好...但是在任何地方都没有提到变量模板?

如果我的多个翻译单元中有以下内容:

template<typename T>
T my_data{};

inline void test() {
    my_data<int> = 1;
}

将为每个翻译单元赋予它们自己的my_data定义,从而产生多个符号,或者将它们全部有效地合并到程序中的单个定义中,从而在一个翻译单元中调用test()修改另一个翻译单元的变量?

标准在何处提及此行为?

1 个答案:

答案 0 :(得分:1)

根据c ++ 14标准[basic.def]/4

  

每个程序应在被丢弃的语句之外,确切地包含该程序中奇特使用的每个非内联函数或变量的一个定义;无需诊断。

因此,如果my_data<T>在多个翻译单元中与相同的模板参数一起使用,则应该出现odr-violation(无任何诊断)的情况。 inline变量出现在c ++ 17中以解决该问题,这就是为什么type_traits * _v系列变量模板被声明为inline的原因。

在实践中,使用Gcc和Clang(至少,我无法检查其他编译器),您不会遇到任何odr违例,因为模板变量具有“模糊链接”(就像它们是内联声明的一样)。

您可以使用nm进行检查。如果运行此命令行g++ -c test.cpp -std=c++14 && nm test.o | c++filt | grep my_data,应该看到my_data<int>是类别u的符号,根据nm文档:

  

该符号是唯一的全局符号。这是对ELF符号绑定的标准集合的GNU扩展。对于这样的符号,动态链接程序将确保在整个过程中只有一个使用此名称和类型的符号。


Core issue #1849中,可以读懂这个晦涩的句子:

  

在6.2 [basic.def.odr]第6段中,关于何时可以在程序中多次声明实体的描述不是,但应该讨论变量模板。

我敢打赌,如果所有编译器都给变量模板提供模糊的链接,那么将来对该标准的修订可能会反映出这一点。但是现在我们应该像在stl中那样使用内联说明符。