【问题标题】:Are static locals of function template specializations with T=<unnamed namespaced class> required to be unique?具有 T=<unnamed namespaced class> 的函数模板特化的静态局部变量是否需要唯一?
【发布时间】:2016-01-20 15:26:57
【问题描述】:

我们使用英特尔 C++ 编译器并检测到它错误编译 (?) 以下内容,从使用 boost::function&lt;Ponies()&gt; f(unnamedNamespacedFunctor) 减少。

a1.cc:

template<typename T>
int f(T) { static int x = T::x; return x; }


namespace { struct A { static const int x = 1; }; }

int f1() {
   return f(A());
}

a2.cc:

template<typename T>
int f(T) { static int x = T::x; return x; }


namespace { struct A { static const int x = 0; }; }

int f2() {
   return f(A());
}

main.cc:

#include <cstdio>

int f1();
int f2();

int main() {
   std::printf("%d != %d\n", f1(), f2());
} 

命令行:

# icpc a1.cc a2.cc main.cc -o main
# ./main
0 != 0

我的问题是:这符合要求吗?在这种实例化中使用静态局部变量会产生未定义的行为吗?在检查生成的符号时,我注意到虽然f 具有本地链接,但正如我所怀疑的那样,x 静态变量接收弱链接,因此两个x'es 被合并,它变成了被选中的彩票

# icpc a2.cc a1.cc main.cc -o main
# ./main
1 != 1

我将不胜感激。也许这毕竟是一个编译器错误并且已经被报告了?

【问题讨论】:

  • 如果您将struct A 之一重命名为例如struct B?
  • f的定义不是违反了ODR吗?如果您将f 的两个定义放在它们各自的本地命名空间中以修复 ODR 违规,会发生什么?
  • @MSalters 对于 boost::function 也是如此,我无法轻易更改它:) 如果它违反了 ODR,我想这违反了现有做法。我还没有找到禁止这个的规则。函数模板实例化的链接是外部的,但参数类型具有内部链接(因此在不同的 TU 中是不同的类型!)。我找不到禁止它的段落,我不确定是否有禁止它的理由。
  • @JohannesSchaub-litb:您如何最终得到 Boost.function 的两个定义?宏? ODR主要是说token序列必须相同,当然token含义在实例化后可能会有所不同。毕竟,这就是模板的全部意义所在。
  • @MSalters 我只是创建了一个boost::function&lt;int()&gt; f(MyTuLocalFunctor());,它随机地将一个.cc 仿函数的行为替换为另一个.cc 仿函数的行为。事实证明,原因是它合并了静态局部变量,boost::function 使用它在内部实现其类型擦除。

标签: c++ templates static undefined-behavior icc


【解决方案1】:

这对我来说似乎是一个错误。让A1 成为A 的一个实例,而A2 是另一个:

我认为静态 x 具有弱链接,因此链接器可以在 same 实例的多个副本之间合并静态副本。 (例如,如果您设法在两个不同的翻译单元中实例化 f&lt;A1&gt;。)

f&lt;A1&gt;f&lt;A2&gt; 都应该有不同的名称修饰,这将导致 x 的两个版本具有不同的名称修饰(我认为某些编译器实际上会生成一个随机值以使匿名命名空间内的名称唯一) , 否则 x 不应该有内部链接(因为使用本地类型来实例化 f,这应该使得它无法在另一个翻译单元中复制)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-13
    • 1970-01-01
    • 1970-01-01
    • 2017-11-10
    • 2013-10-16
    相关资源
    最近更新 更多