开发者

What is the initialization order for static data members of template class in a file?

In a given file if I have,

struct A { static int a; };
struct B { static int b; };
int A::a;
int B::b;

Then, I can always expect that A::a gets initialized before B::b. Now for the same file, take the template case,

template<typename T>
struct X { static T t; };
template<typename T>
T X<T>::t;

Suppose, X is instantiated with A and B and its static member is used arbitrarily somewhere in the code as, X<A>::t and X<B>::t, then what should be the order for initialization of template static member X<T>::t; ? Is i开发者_如何学Ct well defined ?


As long as the templates only have one definition (e.g. you only have one translation unit), it's well-defined. The static members are initialized in the order that the template specializations are instantiated in contexts that require the definition of the static data member. From §14.7.1/1 [temp.inst] of the C++03 standard (emphasis mine):

Unless a class template specialization has been explicitly instantiated (14.7.2) or explicitly specialized (14.7.3), the class template specialization is implicitly instantiated when the specialization is referenced in a context that requires a completely-defined object type or when the completeness of the class type affects the semantics of the program. The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions or default arguments, of the class member functions, member classes, static data members and member templates; and it causes the implicit instantiation of the definitions of member anonymous unions. Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated side-effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.

§14.7.1/7 also states:

The implicit instantiation of a class template does not cause any static data members of that class to be implicitly instantiated.

However, things get more complicated when you have multiple translation units that define the template. §3.2/5 [basic.def.odr] states:

There can be more than one definition of a class type (clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template (clause 14), non-static function template (14.5.5), static data member of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for which some template parameters are not specified (14.7, 14.5.4) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then

(list of conditions...)

If the definitions of D satisfy all these requirements, then the program shall behave as if there were a single definition of D. If the definitions of D do not satisfy these requirements, then the behavior is undefined.

Note that the standard doesn't specify which definition is taken as the single definition, only that some definition is chosen. So, if multiple translation units instantiate the templates in different orders, there's no guarantee what the order of initialization will be.


Following is my observation (based on gcc):

Whatever appears first, is instantiated first.

If in a given translation unit (i.e. preprocessed .cpp file), if the compiler (parser) sees the usage X<A>::t first then it's instantiated first or if it sees X<B>::t first then that is instantiated first. Note, that this is before compilation (not runtime).

For example,

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();
}

Result:

X<B>::t instantiated first
X<A>::t instantiated second

Reason:

X<B>::t appears first inside foo()


From the C++0x draft standard, section 3.6.2:

Dynamic initialization of a non-local variable with static storage duration is either ordered or unordered. Definitions of explicitly specialized class template static data members have ordered initialization. Other class template static data members (i.e., implicitly or explicitly instantiated specializations) have unordered initialization. Other non-local variables with static storage duration have ordered initialization. Variables with ordered initialization defined within a single translation unit shall be initialized in the order of their definitions in the translation unit.

So to answer your question, static data members of explicitly-instantiated templates are not guaranteed to be initialized in any particular order in C++0x.

I leave it to others to find the corresponding language (or lack thereof) in the earlier standard(s).


From 14.7.2/7:

The explicit instantiation of a class template specialization implies the instantiation of all of its members not previously explicitly specialized in the translation unit containing the explicit instantiation.

So we can conclude that templates that are explicitly instantiated have their static members instantiated/constructed in the same order.

For implicitly instantiated templates however, we go to 14.7.1/1:

...in particular, the initialization (and any associated side effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.

From this I don't think we can safely draw any conclusions about the order in which they may be instantiated for implicitly instantiated templates.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜