Reputation:
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
}
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
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
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
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