2017-02-17 74 views
0

以下声明在声明3.8.1中失败,但似乎在其他测试编译器(例如gcc 6.1,MSVC 2015,clang 3.9.1)中没有错误地编译。constexpr实例的初始化(例如`std :: integral_constant`)是否需要`= {}`?

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

铛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,以便用户可以避免键入={}

回答

1

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

没有简单默认构造函数的类型将在默认初始化下为未初始化。通常这很好。

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

这不应该被认为是一个问题。一般来说,你应该总是明显地初始化一个constexpr变量,即使它只是= {}。这样,每个人都清楚你在做什么。

不,你不应该添加默认的构造函数类型只是为了让人们可以使他们的变量constexpr没有明显的初始化它们。如果类型需要一个才能完成其工作,则只应将用户提供的默认构造函数添加到类型中。


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

+0

'std :: integral_constant'没有值表示(它是一个空的结构体)。你的“你应该总是明显地初始化”规则是否仍然适用? –

+0

@RossBencina:“* std :: integral_constant没有值表示*”标准很清楚,所有'constexpr'变量都应该被初始化。它是否具有价值表现并不是标准关心的问题。在constexpr函数中声明的任何变量也是如此。 –

+0

这个答案目前没有解决我的问题“这是怎么回事?” - 为什么不同编译器之间的行为不同?哪个编译器是正确的? –

0

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

报价CWG活跃的问题#253:

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

[]

第9段[dcl.init]表示:

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

如果const POD对象没有非静态数据成员会怎么样? 这一措词需要这样的情况下一个空的初始化[...]

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

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

注意,2011会议:

如果隐含的默认构造函数初始化所有子对象,应该不需要初始化。

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

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