我试图通过以下示例了解变量模板的工作原理:
#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
}
老实说,我真的不知道这种行为。困扰我的是专业化var<T, t>
为0,但y.a
为31
。此外,如果我们使用临时初始化类型T
的对象,我们也会有不同的结果。你能澄清一点吗?
我的意思是,我正在寻找工作草案N4296
的规范性参考,描述这种行为。
答案 0 :(得分:9)
目前,变量模板尚未明确。如果我们通过the current core issues list,我们会看到
以前还不清楚初始化顺序变量模板的后续内容。 CWG issue 1744修改了[basic.start.init] / p2以澄清
使用静态存储动态初始化非局部变量 如果变量是隐式或者,则duration unordered 显式实例化特化,否则有序 [注意:明确专门的静态数据成员或变量 模板特化已订购初始化。 - 结束记录]。
var<T, t>
是一个非局部变量,其静态存储持续时间是隐式实例化的特化。因此,它的动态初始化是无序的。由于t
没有资格进行常量初始化,这意味着可以在var<T, t>
的动态初始化之前初始化t
,结果产生0,无论两者之间的相对顺序如何var
的定义和t
的定义,无论var<T, t>
的实例化点如何。
因此,moving the definition of var
below the definition of t
和/或an explicit instantiation of var<T, t>
对正在打印的内容没有影响,而providing an explicit specialization for var<T, t>
still initializing it to t.a
会导致第一行打印31
。
答案 1 :(得分:3)
原因是初始化顺序:
首先是零初始化。所有三个变量都设置为零。
然后是常量初始化。使用y
初始化tt
和constexpr
,结果为31。
动态初始化是最后一个。在此步骤中,编译单元中变量的顺序很重要。 var
位于t
之前,因此var<T, t>
在t
初始化t
之前初始化y
。
答案 2 :(得分:2)
据推测,var
特化是在其他全局变量之前动态初始化的。在这种情况下,t
需要动态初始化(因为它的初始化不是常量表达式),因此在用于初始化var<T, t>
时仍然具有零值;虽然tt
可以从其constexpr
初始化程序进行静态初始化,但在用于初始化var<T, tt>
时也是如此。
但是,我在draft standard中找不到任何内容来说明这是否是预期的(因为如果专业化的声明点是模板本身的那一点),或未定义/不正确的行为