【问题标题】:Does initialization of constexpr instance (e.g. `std::integral_constant`) require `={}`?constexpr 实例的初始化(例如`std::integral_constant`)是否需要`={}`?
【发布时间】:2017-07-06 12:41:47
【问题描述】:

以下声明在 clang 3.8.1 中失败,但似乎在其他经过测试的编译器中编译没有错误(例如 gcc 6.1、MSVC 2015、clang 3.9.1)。

constexpr std::integral_constant<int,0> myConstant;

clang 3.8.1 给出:

error: default initialization of an object of const type 'const std::integral_constant<int, 0>' without a user-provided default constructor constexpr std::integral_constant<int,0> myConstant;

而以下在所有测试的编译器中都正确编译:

constexpr std::integral_constant<int,0> myConstant = {};

这里发生了什么? (clang 3.8.1的错误正确吗?)

如果我定义自己的类型,我是否应该编写一个用户提供的默认 ctor 以便用户可以避免输入 ={}

【问题讨论】:

    标签: c++11


    【解决方案1】:

    constexpr 变量必须被初始化。 Typename variablename; 形式的声明将对variablename 执行默认初始化。

    没有普通默认构造函数的类型在默认初始化下将未初始化。一般没问题。

    constexpr 变量不允许未初始化。因此,对于具有琐碎默认构造函数的类型,您必须明显地初始化它们。通过对变量执行= {},会导致它被初始化,这将使对象清零。

    这不应被视为问题。通常,您应该始终以可见方式初始化constexpr 变量,即使它只是使用= {}。这样,每个人都清楚你在做什么。

    不,你不应该将默认构造函数添加到类型中,这样人们就可以在没有明显初始化它们的情况下创建它们的constexpr 变量。如果类型需要来完成它的工作,你应该只添加一个用户提供的默认构造函数。


    至于编译器的行为,就在他们身上。 Clang 在 3.8.1 中的行为在规范方面是正确的,所以其他的都是不正确的。

    【讨论】:

    • std::integral_constant 没有值表示(它是一个空结构)。您的“您应该始终以可见的方式初始化”规则仍然适用吗?
    • @RossBencina: "std::integral_constant 没有值表示" 标准非常明确,所有constexpr 变量“都应该被初始化”。它是否具有价值表示并不是标准所关心的。在constexpr 函数中声明的任何变量也是如此。
    • 这个答案目前没有解决我的问题“这里发生了什么?” -- 为什么不同编译器的行为不同?哪个编译器是正确的?
    • @RossBencina:鉴于我对 标准 要求的解释,我认为“哪个编译器是正确的”的答案是显而易见的。但我已经让答案更明确了。
    • @RossBencina:然后它有一个回归,因为你说 3.8.1 工作(即:给出了一个错误)。我已经解释了 C++ 标准所说的应该发生的事情。您可以根据具体的编译器版本来判断,并根据需要在其上提交错误。
    【解决方案2】:

    根据这个答案:https://stackoverflow.com/a/28338265/2013747,是否需要={}是clang和gcc最初选择以不同方式实现的一个悬而未决的问题。允许省略 ={} 似乎是 CWG 首选的方向,clang 3.9 更改了策略以反映这一点。

    引用 CWG 活跃问题 #253:

    253.为什么必须初始化空或完全初始化的 const 对象?

    []

    8.6 [dcl.init] 的第 9 段说:

    如果没有为对象指定初始化器,并且对象是(可能 >cv 限定的)非 POD 类类型(或其数组),则该对象应 >default-initialized;如果对象是 const 限定类型,则基础 >class 类型应具有用户声明的默认构造函数。否则,如果没有为对象指定 >initializer,则该对象及其子对象(如果有)具有不确定的初始值;如果对象或其任何子对象>属于 const-qualified 类型,则程序格式错误。

    如果 const POD 对象没有非静态数据成员怎么办? 对于这种情况,这种措辞需要一个空的初始化器 [...]

    (添加了重点。)这里的结论是,为了与旧编译器兼容,并严格遵守标准,除非有用户声明的默认 ctor,否则必须使用 ={}

    旧的 clang 行为源于上述保守的解释 的语言规范。 CWG 2011 年 8 月会议决议:

    2011 年 8 月会议记录:

    如果隐式默认构造函数初始化所有子对象,则不需要初始化器。

    来源:http://open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#253

    据我所知,此更改尚未纳入任何版本的 C++ 标准。因此,虽然省略 ={} 可能会继续编译,并且将来可能会被标准正式支持,但它目前不是官方 ISO 标准的一部分。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-05
      • 2020-06-26
      • 2013-10-18
      相关资源
      最近更新 更多