【问题标题】:Understanding variable templates by example通过示例了解变量模板
【发布时间】:2015-04-09 12:36:59
【问题描述】:

我试图通过以下示例了解变量模板的工作原理:

#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&lt;T, t&gt; 是 0,但 y.a31。此外,如果我们用临时初始化 T 类型的对象,我们也会得到不同的结果。你能澄清一下吗?

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

【问题讨论】:

标签: c++ templates c++14


【解决方案1】:

目前,变量模板的指定程度相当低。如果我们通过the current core issues list,我们会看到

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

使用静态存储动态初始化非局部变量 如果变量是隐式或 显式实例化的特化,否则是有序的 [注意:明确专门化的静态数据成员或变量 模板专业化已订购初始化。 —结束注释]。

var&lt;T, t&gt; 是一个具有静态存储持续时间的非局部变量,它是隐式实例化的特化。因此它的动态初始化是无序的。由于t 不符合常量初始化条件,这意味着var&lt;T, t&gt; 可能在t 的动态初始化之前被初始化,结果产生0,而不管var 的定义和@ 之间的相对顺序如何987654337@的定义,和var&lt;T, t&gt;的实例化点无关。

因此,moving the definition of var below the definition of t 和/或an explicit instantiation of var&lt;T, t&gt; 对正在打印的内容没有影响,而providing an explicit specialization for var&lt;T, t&gt; still initializing it to t.a 导致第一行打印31

【讨论】:

  • 除了标准中的缺陷之外,[basic.start.init]/2 中的语句不是“具有静态存储持续时间的非局部变量的动态初始化是无序的 如果变量是隐式或显式实例化的特化,否则是有序。"在这里申请? var&lt;T, t&gt; 既是“具有静态存储持续时间的非局部变量”又是“隐式实例化的特化”。
  • @Casey 嗯,这不在我用于 C++14 的 N4140 中。是来自 N4296 的吗?
  • 澄清一下,如果变量是隐式或显式实例化的特化,则具有静态存储持续时间的非局部变量的动态初始化是无序的,否则是有序的,即只有可变模板可能有无序初始化。
【解决方案2】:

原因是初始化的顺序:

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

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

  • 动态初始化是最后一个。在这一步中,编译单元中变量的顺序很重要。 vart 之前,所以var&lt;T, t&gt;ty 初始化之前从t 初始化。

【讨论】:

  • 初始化不是一个多遍过程。
  • @AndyProwl:是的。 [basic.start.init] 详细描述了它,这是一个不错的总结。
  • 是的,对不起大家。我发疯了。
  • 我编辑了答案,因为否则我不允许撤回我不正确的反对票。随时恢复到原始版本。
  • Moving var below t 什么都不做。我认为 clang 可能遵循与类模板静态数据成员相同的规则 - 那些具有无序初始化。
【解决方案3】:

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

但是,我在draft standard 中找不到任何内容来说明这是预期的(如果特化的声明点是模板本身的声明点),还是未定义/不正确的行为。

【讨论】:

  • [大声思考]:OTOH,如果y 被声明为const,行为不会改变。我想这还不足以保证通过 constexpr 构造函数进行编译时初始化。
  • @AndyProwl:我猜你的意思是y。它必须是constexpr,而不仅仅是const,才能在常量表达式中使用(如果它们只是const,则可以使用整数和枚举,但不能使用其他类型)。
  • CWG issue 1845。快速搜索问题列表似乎表明变量模板在许多其他方面未指定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-06
  • 2017-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多