2

I have a question related to a previous question posted here Static field initialization order Suppose I have the following struct, with 2 static members x and y (templated types themselves)

#include <iostream>

using namespace std;

template <typename T>
struct Foo
{
    static T x;
    static T y;
    Foo()
    { 
         cout << "x = " << x << endl;
         cout << "y = " << y << endl;
    }
};

template <typename T>
T Foo<T>::x = 1.1f;

template <typename T>
T Foo<T>::y = 2.0 * Foo<T>::x;


int main()
{
    Foo<double> foo;
}

Output:

x = 1.1 
y = 2.2

I initialize x and y above main(), and you can see that y depends on x, so it better be that x is initialized first.

My questions:

  1. At the point of initialization, the types of x and y are still unknown, so when are they really initialized? Are the static members actually initialized after the template instantiation Foo<double> foo; in main()?
  2. And if yes, the order of declarations of x and y seems not to matter, i.e. I can first declare y then x (both in the struct and in the static initialization) and still get the correct output, i.e. the compiler knows somehow that y is dependent on x. Is this a well defined behaviour (i.e. standard-compliant)? I use g++ 4.8 and clang++ on OS X.

Thanks!

Community
  • 1
  • 1
vsoftco
  • 55,410
  • 12
  • 139
  • 252
  • I deleted my answer, you probably require someone with more standardese knowledge, sorry! – user657267 May 24 '14 at 03:58
  • @user657267 no problem, I am extremely curious about an answer actually, as I cannot find a satisfactory one anywhere. – vsoftco May 24 '14 at 04:01

1 Answers1

3

This code is safe because Foo<double>::x has constant initialization, but Foo<double>::y has dynamic initialization.

3.6.2/2:

Constant initialization is performed:

  • ...

  • if an object with static or thread storage duration is not initialized by a constructor call and if every full-expression that appears in its initializer is a constant expression.

Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization. Static initialization shall be performed before any dynamic initialization takes place.

On the other hand, if you had:

double tmp = 1.1;

template <typename T>
T Foo<T>::x = tmp;

template <typename T>
T Foo<T>::y = 2.0 * Foo<T>::x;

that code would not be "safe" - Foo<double>::y could end up being either 2.2 or 0.0 (assuming nothing else modifies tmp during dynamic initializations).

Community
  • 1
  • 1
aschepler
  • 70,891
  • 9
  • 107
  • 161
  • Ok, thanks much for clarifying this part, +1. However, how does the line `template T Foo::x = 1.1f;` really work? The type is not known at the declaration, is the static member initialized by a `float` by default, regardless of `T`? Or is it really initialized only after `Foo foo;`? This is the part that puzzles me the most. – vsoftco May 24 '14 at 04:10
  • When the compiler sees `Foo`, it instantiates the class only to determine the names and types of all the class's members. Then `Foo foo;` uses a default constructor, so the function definition for `Foo::Foo()` is instantiated. That definition uses members `x` and `y`, so the member definitions for `Foo::x` and `Foo::y` are instantiated. The compiler sets up permanent objects for them with initial value and/or code to do the initialization. The initialization actually happens when the program is executed. – aschepler May 24 '14 at 04:21
  • Ok, makes perfect sense now! Thanks! – vsoftco May 24 '14 at 04:23
  • I don't think this is correct: globals in the same TU are initialized in the same order they are defined. In the code above, the initialization order is guaranteed to be tmp, x, y, and therefore y is guaranteed to be 2.2. – Nir Friedman Jul 19 '18 at 17:06
  • @NirFriedman For non-templates, yes. But [basic.start.dynamic]/1 "Dynamic initialization of a non-local variable with static storage duration is unordered if the variable is an implicitly or explicitly instantiated specialization..." which ends up meaning the order of initialization is indeterminately sequenced (or possibly even unsequenced if threads get involved). – aschepler Jul 19 '18 at 23:39
  • Does the standard use the word specialization differently? There is no specialization here, as I understand it. Does the standard use specialization simply to refer to any concrete instantiation if a template, even if there is only a primary definition? If so then my question is addressed. – Nir Friedman Jul 20 '18 at 06:26