我不明白编译器在这里做了什么:
#include <iostream>
using namespace std;
// non-default-constructable struct
struct X
{
X(int v) : x(v) {}
const int x;
};
template< typename T>
struct A
{
static const X a;
};
// trigger a compiler error if we try to instantiate the default template
template< typename T >
const X A<T>::a;
template<>
struct A<int>
{
static const X a;
};
template<>
struct A<float>
{
static const X a;
};
// is this not infinitely circular?
const X A<int>::a = X(A<float>::a.x + 1);
const X A<float>::a = X(A<int>::a.x + 1);
int main() {
// error as expected, A<bool>::a cannot be default-constructed
// cout << A<bool>::a.x << endl;
// this compiles and prints "1 2"
cout << A<int>::a.x << " " << A<float>::a.x << endl;
return 0;
}
我原本期望a
的两个专门定义产生编译器错误,因为它们都是使用另一个的值初始化的,并且甚至没有默认构造函数可以依赖。但显然,这会在ideone中编译并打印1 2
。那么编译器如何得出X
的两个实例应该用这些值初始化的结论呢?
答案 0 :(得分:4)
这恰好是非局部变量初始化的副作用。标准说:
3.6.2非局部变量的初始化[basic.start.init]
...
...具有静态存储持续时间(3.7.1)或线程存储持续时间(3.7.2)的变量应为零初始化(8.5) 在进行任何其他初始化之前... ... ...在进行任何动态初始化之前,应执行静态初始化。 如果变量是a,则具有静态存储持续时间的非局部变量的动态初始化是无序的 隐式或显式实例化的特化,否则是有序的[注意:一个明确的专门化 静态数据成员或变量模板特化已经有序初始化。 - 尾注]变量 在单个翻译单元中定义的有序初始化应按其顺序初始化 翻译单位中的定义。
这就是这里发生的事情:
A<int>::a
和A<float>::a
均为0初始化A<int>::a
读取A<float>::a
中的内容,因为之前的0初始化为0,添加1并完全初始化为1 A<float>::a
获取现已完全初始化的A<int>::a
的值,该值为1,加1并完全初始化为2 这意味着这是一个结构良好的计划。
但同一段后来说:
如果对象obj1的初始化引用了命名空间范围的对象obj2 可能需要动态初始化并在稍后的同一翻译单元中定义,它是未指定的 是否使用obj2的值将是完全初始化的obj2的值(因为obj2是静态的 初始化)或将是obj2的值仅为零初始化
所以我不确定输出是否需要为1 2,或者如果A<int>::a
的动态初始化首先触发A<float>::a