模板变量是不是允许在多个翻译单元中并有效合并?

Posted

技术标签:

【中文标题】模板变量是不是允许在多个翻译单元中并有效合并?【英文标题】:Are template variables allowed within multiple translation units and effectively merged?模板变量是否允许在多个翻译单元中并有效合并? 【发布时间】:2018-10-03 15:00:54 【问题描述】:

请参阅以下内容:

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() 将修改变量为另一个翻译单位?

标准中哪里提到了这种行为?

【问题讨论】:

这看起来像是this question的更通用版本 是否有您关心的特定 C++ 版本(如 C++17?),或者每个版本都支持变量模板? C++14 特别是,但我假设它对于任何支持变量模板的解释都是相同的。我试图弄清楚我正在做的事情是否属于 NDR ......但该程序似乎在 Clang 下表现正确。 【参考方案1】:

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

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

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

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

您可以通过nm查看。如果您运行此命令行g++ -c test.cpp -std=c++14 &amp;&amp; nm test.o | c++filt | grep my_data,您应该看到my_data&lt;int&gt;u 类别的符号,这是根据nm 文档:

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


在Core issue #1849 可以读到这个晦涩的句子

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

我敢打赌,如果所有编译器都给变量模板一个模糊的链接,那么未来的标准修订版可能会反映这一点。但现在我们应该使用 inline 说明符,就像在 stl 中所做的那样。

【讨论】:

以上是关于模板变量是不是允许在多个翻译单元中并有效合并?的主要内容,如果未能解决你的问题,请参考以下文章

为啥模板类函数必须在同一个翻译单元中声明?

静态时序分析圣经翻译计划10——第五章:延迟计算 (下)

第五章: 延迟计算 下静态时序分析圣经翻译计划

静态、全局和多个翻译单元

C++ 编译与翻译单元

Django - 在渲染到模板之前翻译变量