C++11 constexpr实例(例如“std::integral_constant”)的初始化是否需要“={}”?

C++11 constexpr实例(例如“std::integral_constant”)的初始化是否需要“={}”?,c++11,C++11,以下声明在clang 3.8.1中失败,但在其他测试的编译器(如gcc 6.1、MSVC 2015、clang 3.9.1)中编译时似乎没有错误 constepr std::积分常数myConstant; clang 3.8.1给出了: 错误:在没有用户提供的默认构造函数的情况下,默认初始化常量类型为“const std::integral_constant”的对象 constexpr std::积分常数myConstant 鉴于以下各项在所有测试的编译器中都能正确编译: constexpr

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

constepr std::积分常数myConstant;
clang 3.8.1给出了:

错误:在没有用户提供的默认构造函数的情况下,默认初始化常量类型为“const std::integral_constant”的对象
constexpr std::积分常数myConstant

鉴于以下各项在所有测试的编译器中都能正确编译:

constexpr std::integral_constant<int,0> myConstant = {};
constepr std::integral_常量myConstant={};
这是怎么回事?(clang 3.8.1错误是否正确?)


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

constepr
变量必须初始化。形式为
Typename variablename的声明
将在
variablename
上执行默认初始化

在默认初始化下,没有普通默认构造函数的类型将被取消初始化。通常情况下,这很好

但是
constexpr
变量不允许未初始化。因此,对于具有普通默认构造函数的类型,必须对其进行可见的初始化。通过对变量执行
={}
操作,将使其值初始化,从而使对象归零

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

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


至于编译器行为,这取决于它们。就规范而言,3.8.1中的Clang行为是正确的,因此其他行为是不正确的。

根据这个答案:,是否需要
={}
是Clang和gcc最初选择以不同方式实现的一个开放问题。允许省略
={}
似乎是CWG首选的方向,而Clang3.9改变了策略以反映这一点

引用CWG现行问题253:

253。为什么必须初始化空的或完全初始化的常量对象

[]

8.6[dcl.init]第9段规定:

如果没有为对象指定初始值设定项,并且该对象是(可能>cv限定的)非POD类类型(或其数组),则该对象应>默认初始化;如果对象是const限定类型,则底层>类类型应具有用户声明的默认构造函数。否则,如果没有为对象指定>初始值设定项,则该对象及其子对象(如果有)具有不确定的初始值;如果对象或其任何子对象的>类型为常量限定类型,则程序的格式不正确

如果constpod对象没有非静态数据成员该怎么办对于此类情况,此措辞需要一个空的初始值设定项[…]

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

这种古老的叮当声源于上述保守的解释 语言规范的定义。CWG 2011年8月会议决定:

2011年8月会议记录:

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

资料来源:


据我所知,这种变化尚未被纳入任何版本的C++标准。因此,尽管省略

={}
可能会继续编译,并且将来可能会得到该标准的正式支持,但它目前不是官方ISO标准的一部分。

std::integral_constant
没有值表示(它是一个空结构)。您的“您应该始终可见地初始化”规则仍然适用吗?@RossBencina:“std::integral_常量没有值表示法”标准非常明确,所有
constexpr
变量“都应该初始化”。标准并不关心它是否有值表示。在
constexpr
函数中声明的任何变量也是如此。这个答案目前没有回答我的问题“这里发生了什么?”--为什么不同编译器的行为不同?哪个编译器是正确的?@RossBencina:考虑到我对标准要求的解释,我认为“哪个编译器是正确的”的答案是显而易见的。但是我已经把答案说得更清楚了。@RossBencina:那么它有一个回归,因为你说3.8.1有效(即:给出了一个错误)。我已经解释了C++标准应该发生什么。您可以根据需要根据特定的编译器版本和它们上的文件错误来判断。
constexpr std::integral_constant<int,0> myConstant = {};