user2953119
user2953119

Reputation:

Understanding variable templates by example

I'm trying to understand how variable templates work by the following example:

#include <iostream>

template <class T, const T& t>
int var = t.a;

struct T
{
    int a;
    constexpr T(): a(31){ }
};

T y;

const T t = y;

const T tt = T();

int main()
{ 
    std::cout << "var <T, t> = " << var<T, t> << std::endl;  //0
    std::cout << "y.a = " << y.a << std::endl;  //31
    std::cout <<"var <T, tt> = " << var<T, tt> << std::endl; //31
}

DEMO

Honestly I have really no idea about that behavior. The thing that confused me was that the specialization var<T, t> is 0, but y.a is 31. Also, if we initialize the object of the type T with temporary we also have different results. Could you clarify that a bit?

I mean, I'm looking for a normative reference from the working draft N4296, describing that behavior.

Upvotes: 16

Views: 511

Answers (3)

T.C.
T.C.

Reputation: 137425

Variable templates are rather underspecified at the moment. If we go through the current core issues list, we see that

It also used to be unclear what initialization order variable templates follow. CWG issue 1744 modified [basic.start.init]/p2 to clarify that

Dynamic initialization of a non-local variable with static storage duration is unordered if the variable is an implicitly or explicitly instantiated specialization, and otherwise is ordered [Note: an explicitly specialized static data member or variable template specialization has ordered initialization. —end note].

var<T, t> is a non-local variable with static storage duration that is an implicitly instantiated specialization. Therefore its dynamic initialization is unordered. Since t doesn't qualify for constant initialization, that means that var<T, t> may be initialized before the dynamic initialization of t, producing 0 as a result, regardless of the relative order between var's definition and t's definition, and regardless of the point of instantiation of var<T, t>.

Thus, moving the definition of var below the definition of t and/or an explicit instantiation of var<T, t> has no effect on what's being printed, while providing an explicit specialization for var<T, t> still initializing it to t.a causes the first line to print 31.

Upvotes: 9

StenSoft
StenSoft

Reputation: 9617

The reason is the order of initialization:

  • First is zero initialization. All three variables are set to zero.

  • Then is constant initialization. y and tt are initialized using constexpr which yields 31.

  • Dynamic initialization is the last one. In this step, the order of variables in the compilation unit is important. var is before t and so var<T, t> is initialized from t before t is initialized from y.

Upvotes: 3

Mike Seymour
Mike Seymour

Reputation: 254631

Presumably, the var specialisations are dynamically initialised before the other global variables. In that case, t needs dynamic initialisation (since it's initialiser isn't a constant expression), so still has a zero value when used to initialise var<T, t>; while tt can be statically initialised from its constexpr initialiser, so has its final value when used to initialise var<T, tt>.

However, I can't find anything in the draft standard to say whether this is expected (as it would be if the point of declaration of the specialisations were that of the template itself), or undefined/incorrect behaviour.

Upvotes: 2

Related Questions