我们使用英特尔C++编译器,并检测到它在以下代码中进行了误编译,该代码从使用boost::function<Ponies()> f(unnamedNamespacedFunctor)精简而来。
a1.cc:
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
被合并,就像抽奖一样随机选择了一个。
# icpc a2.cc a1.cc main.cc -o main
# ./main
1 != 1
我需要帮助,或许这实际上是编译器的一个bug,而且已经被报告了吗?
f
的定义不违反ODR吗?如果将f
的两个定义放在各自的本地命名空间中以修复ODR违规,会发生什么? - MSaltersboost::function<int()> f(MyTuLocalFunctor());
,它随机地将一个 .cc 函数对象的行为替换为另一个 .cc 函数对象的行为。结果发现原因是它合并了静态局部变量,而 boost::function 使用这些变量在内部实现其类型擦除。 - Johannes Schaub - litbf<T>
的实例化不被内联到f1
和f2
中(可能需要使用__attribute__((noinline))
),则应该能够看到这些实例化是否具有相同的名称混编。 根据 Itanium C ++ ABI,函数作用域名称的名称混编包括函数的名称混编,我肯定会期望两个实例化具有不同的名称混编。 我怀疑在内联时 icpc 存在错误。 - John Calsbeek