Do typedefs of templates preserve static initialization order?
c++, initialization, static, templates, typedef
Solution
Within the same compilation unit, the C++ standard says that static initialization order is well defined -- it's the order of the declarations of the static objects.
In your shown code you have no declaration of a static data member. You have a declaration of a typedef-name. These have nothing to do with that, and don't influence any order. You probably think along this way:
If i make that typedef declaration, it will instantiate `helper<int>`, and thus instantiate its static data member declaration first.
The problem is, that line does not cause an instantiation of `helper<int>`. For that to happen, you would need an explicit instantiation or manage to make it instantiate it implicitly (creating an object of `helper<int>` for example, or using it as a nested name specifier as in `helper<int>::...` and explicitly referencing the static member - otherwise, creation of it is omitted).
But there is a much deeper problem. The order is not the declaration of the static data-members. The order is their definition. Consider the following
struct C { C() { printf("hey\n"); } };
struct A {
static C a;
static C b;
};
C A::b;
C A::a;
In this code, b is created before a, even though a is declared before b.
The following code prints `2 1`:
struct C { C(int n) { printf("%d\n", n); } };
template<int N>
struct A {
static C c;
};
template<int N>
C A<N>::c(N);
// explicit instantiation of declaration and definition
template struct A<2>;
template struct A<1>;
int main() {
}
But the following code prints nothing, unless you comment in the line in `main`.
struct C { C(int n) { printf("%d\n", n); } };
template<int N>
struct A {
static C c;
};
template<int N>
C A<N>::c(N);
// implicit instantiation of declarations
A<2> a2;
A<1> a1;
int main() {
// A<1>::c; A<2>::c;
}
I'm not actually sure what the correct output for this second snippet is. Reading the Standard, i can't determine an order. It says at `14.6.4.1` "Point of Instantiation":
For a function template specialization, a member function template specialization, or a specialization for a member function or static data member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization [...]. Otherwise, the point of instantiation for such a specialization immediately follows the namespace scope declaration or definition that refers to the specialization.
The point of instantiation of their definitions both appear immediately after the definition of `main`. Which definition is instantiated before the other definition seems to be left unspecified. If anyone knows the answer and khow other compilers behave (GCC prints `1 2` but with the order of the expressions in `main` swapped, prints `2 1`), please let me know in the comment.
For details, see this answer about static object's lifetime.
Problem
Within the same compilation unit, the C++ standard says that static initialization order is well defined -- it's the order of the declarations of the static objects. But using the Sun Studio 12 compiler I'm encountering unintuitive behavior. I've define a templated class `helper<T>` which contains a static member `_data` of type `T` and a static member function that uses `_data` called `foo`. In my .cpp file I have this above main(): ``` struct A { /* some definition */ }; typedef helper<int> s0; typedef helper<A> s1; ``` Notice that the typedef for `helper<int>` comes before the typedef for `helper<A>`. Thus according to the standard I would expect that `helper<int>::_data` will be constructed before `helper<A>::_data` (remember `_data` is a static member). On GCC this is the case, on Sun it is not. This is problematic because A's constructor uses `helper<int>::_data`. I only have one compilation unit, with no earlier potential instantiation of `helper<A>`, so I thought the order should be well defined. Is this a Sun compiler bug, or does the typedef not constitute a definition/instantiation technically? What I mean is, is the Sun compiler's behavior allowed by the standard? I have the following main(): ``` int main() { //Swapping the order of these has no effect on Sun s0::foo(); s1::foo(); } ``` There are no other uses of s0 or s1.