通过示例了解变量模板

Understanding variable templates by 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

老实说,我真的不知道那种行为。令我困惑的是特化 var<T, t> 是 0,但 y.a31。另外,如果我们用临时初始化 T 类型的对象,我们也会得到不同的结果。你能澄清一下吗?

我的意思是,我正在寻找工作草案 N4296 中描述该行为的规范参考。

据推测,var 特化是在其他全局变量之前动态初始化的。在那种情况下,t 需要动态初始化(因为它的初始化器不是常量表达式),因此在用于初始化 var<T, t> 时仍然具有零值;而 tt 可以从其 constexpr 初始化程序静态初始化,因此在用于初始化 var<T, tt>.

时具有其最终值

但是,我在 draft standard 中找不到任何内容来说明这是否是预期的(如果专业化的声明点是模板本身的声明点),或者 undefined/incorrect 行为。

原因是初始化顺序:

  • 首先是零初始化。所有三个变量都设置为零。

  • 然后是常量初始化。 ytt 使用 constexpr 初始化,产生 31.

  • 动态初始化是最后一个。在此步骤中,编译单元中变量的顺序很重要。 vart 之前,因此 var<T, t>t 初始化,然后 ty 初始化。

目前变量模板还未指定。如果我们遍历 the current core issues list,我们会看到

过去也不清楚变量模板遵循什么初始化顺序。 CWG issue 1744 修改了 [basic.start.init]/p2 以阐明

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> 是一个具有静态存储持续时间的非局部变量,它是一个隐式实例化的特化。因此它的动态初始化是无序的。由于 t 不符合常量初始化条件,这意味着 var<T, t> 可能会在 t 的动态初始化之前被初始化,结果生成 0,而不管 [=] 之间的相对顺序如何14=] 的定义和 t 的定义,并且与 var<T, t>.

的实例化点无关

因此,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 导致第一行打印 31