constexpr实例的初始化(例如`std :: integral_constant`)是否需要`= {}`?

时间:2017-02-17 05:46:06

标签: c++11

以下声明在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 = {};

这里发生了什么? (铿锵声3.8.1错误是否正确?)

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

2 个答案:

答案 0 :(得分:1)

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

在默认初始化下,没有普通默认构造函数的类型将是未初始化。通常没关系。

constexpr变量不允许未初始化。因此,对于具有普通默认构造函数的类型,您必须可视地初始化它们。通过对变量执行= {},您将使其初始化值,这将使对象清零。

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

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

至于编译器的行为,那就是它们。 Clang在3.8.1中的行为在规范方面是正确的,因此其他行为是不正确的。

答案 1 :(得分:0)

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

引用CWG活动问题#253:

  

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

     

[]

     

8.6 [dcl.init]第9段说:

     

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

     

如果const POD对象没有非静态数据成员怎么办? 此措辞要求此类案例的空初始值设定项 [...]

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

旧的铿锵行为是由于上述保守的解释所致 语言规范。 CWG 2011年8月会议决定:

  

2011年8月会议记录:

     

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

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

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