C++ 为什么这个循环模板实例化是合法的?

C++ 为什么这个循环模板实例化是合法的?,c++,templates,instantiation,circular-reference,C++,Templates,Instantiation,Circular Reference,我不明白编译器在这里做什么: #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

我不明白编译器在这里做什么:

#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;
}
#包括
使用名称空间std;
//非默认可构造结构
结构X
{
X(intv):X(v){}
常数int x;
};
模板
结构A
{
静态常数xa;
};
//如果尝试实例化默认模板,则触发编译器错误
模板
常数xa::A;
模板
结构A
{
静态常数xa;
};
模板
结构A
{
静态常数xa;
};
//这不是无限循环吗?
常数xa::A=X(A::A.X+1);
常数xa::A=X(A::A.X+1);
int main(){
//错误如预期,无法默认构造A::A

//cout这恰好是非局部变量初始化的副作用。标准规定:

3.6.2非局部变量的初始化[basic.start.init]

具有静态存储持续时间(3.7.1)或线程存储持续时间(3.7.2)的变量应初始化为零(8.5) 在进行任何其他初始化之前…
…应在进行任何动态初始化之前执行静态初始化。 具有静态存储持续时间的非局部变量的动态初始化是无序的,如果该变量是 隐式或显式实例化专门化,否则是有序的[注:显式专门化 静态数据成员或变量模板专门化已命令初始化。-结束说明]变量 如果在单个翻译单元内定义了有序初始化,则应按照其顺序初始化 翻译单位中的定义

这正是这里发生的事情:

  • A::A
    A::A
    都初始化为0
  • 然后按照定义的顺序初始化它们
    • 首先
      A::A
      读取
      A::A
      中的内容,由于之前的0初始化,该内容为0,添加1,并用1完全初始化
    • 然后
      A::A
      获取现在完全初始化的
      A::A
      的值,该值为1,加1,并用2完全初始化
这意味着这是一个结构良好的计划

但同一段后来说:

如果对象obj1的初始化引用命名空间范围的对象obj2 它可能需要动态初始化,稍后在同一翻译单元中定义,未指定 使用的obj2值是否将是完全初始化的obj2的值(因为obj2是静态的) 初始化)或将是obj2的值仅初始化为零


因此,我不确定输出是否需要为12,或者如果
A::A
的动态初始化首先触发
A::A

的动态初始化,它是否可以为2,1不,它不是,它是未定义的行为。A::A在A:A之前没有被赋值,这意味着您只是在读取随机内存