如果我有一个给定的文件,
struct A { static int a; };
struct B { static int b; };
int A::a;
int B::b;
然后,我总是可以预期A::a
会在B::b
之前初始化。现在对于同一个文件,请采用template
案例
template<typename T>
struct X { static T t; };
template<typename T>
T X<T>::t;
假设X
已使用A
和B
进行实例化,其static
成员在代码中的任意位置被任意使用,X<A>::t
和{{1那么X<B>::t
静态成员template
的初始化顺序应该是什么?是否定义明确?
答案 0 :(得分:4)
只要模板只有一个定义(例如,您只有一个翻译单元),它就是定义明确的。静态成员按照在需要定义静态数据成员的上下文中实例化模板专业化的顺序进行初始化。来自C ++ 03标准的§14.7.1/ 1 [temp.inst](强调我的):
除非已明确实例化(14.7.2)或显式专用(14.7.3)类模板特化,否则在需要完全定义的对象类型的上下文中引用特化时,将隐式实例化类模板特化。当类类型的完整性影响程序的语义时。类模板特化的隐式实例化会导致类成员函数,成员类,静态数据成员和成员模板的声明的隐式实例化,而不是定义或默认参数的隐式实例化。它会导致成员匿名联合的定义的隐式实例化。除非已显式实例化或明确专门化类模板或成员模板的成员,否则在需要成员定义存在的上下文中引用特化时,将隐式实例化成员的特化;特别是,静态数据成员的初始化(以及任何相关的副作用)不会发生,除非静态数据成员本身的使用方式需要静态数据成员的定义。
§14.7.1/ 7还指出:
类模板的隐式实例化不会导致该类的任何静态数据成员被隐式实例化。
但是,当您有多个定义模板的翻译单元时,事情变得更加复杂。 §3.2/ 5 [basic.def.odr]声明:
可以有多个类类型的定义(第9节),枚举类型(7.2),带外部链接的内联函数(7.1.2),类模板(第14节),非静态函数模板(14.5) .5),类模板的静态数据成员(14.5.1.3),类模板的成员函数(14.5.1.1),或模板特化,程序中未指定某些模板参数(14.7,14.5.4)只要每个定义出现在不同的翻译单元中,并且定义满足以下要求。鉴于在多个翻译单元中定义了这样一个名为D的实体,那么
(条件清单......)
如果D的定义满足所有这些要求,那么程序应该表现得就像D的单个定义一样。如果D的定义不满足这些要求,那么行为是不确定的。
请注意,标准未指定将定义视为单个定义,仅选择某些定义。因此,如果多个翻译单元以不同的顺序实例化模板,则无法保证初始化顺序是什么。
答案 1 :(得分:1)
以下是我的观察(基于gcc):
无论先出现什么,都会先实例化。
如果在给定的翻译单元(即预处理的.cpp
文件)中,如果编译器(解析器)首先看到使用X<A>::t
,那么它首先被实例化,或者如果它首先看到X<B>::t
那么首先实例化的。注意,这是在编译之前(而不是运行时)。
例如,
struct A { static int a; };
struct B { static int b; };
template<typename T> struct X { static T t; };
template<typename T> T X<T>::t;
void foo ()
{
B *p = &(X<B>::t);
}
int main ()
{
A *p = &(X<A>::t);
foo();
}
结果:
X<B>::t instantiated first
X<A>::t instantiated second
原因:
中
X<B>::t
首先出现在foo()
答案 2 :(得分:1)
来自C++0x draft standard,第3.6.2节:
具有静态存储持续时间的非局部变量的动态初始化是有序的或无序的。显式专用类模板的定义静态数据成员已经有序初始化。其他类模板静态数据成员(即,隐式或显式实例化的特化)具有无序初始化。具有静态存储持续时间的其他非局部变量具有有序初始化。在单个翻译单元中定义的具有有序初始化的变量应按其在翻译单元中的定义顺序进行初始化。
因此,为了回答您的问题,不保证在C ++ 0x中以任何特定顺序初始化显式实例化模板的静态数据成员。
我将其留给其他人在早期标准中找到相应的语言(或缺少相应的语言)。
答案 3 :(得分:1)
从14.7.2 / 7:
类模板特化的显式实例化意味着 以前没有明确说明其所有成员的实例化 专门从事包含显式的翻译单元 实例
因此,我们可以得出结论,显式实例化的模板的静态成员以相同的顺序实例化/构建。
对于隐式实例化的模板,我们转到14.7.1 / 1:
...特别是初始化(以及任何相关的副作用) 除非静态数据成员,否则不会发生静态数据成员 本身以需要定义静态数据的方式使用 成员存在。
由此我不认为我们可以安全地得出关于它们可以被实例化为隐式实例化模板的顺序的任何结论。