给出以下代码:
struct f {
};
int main(){
constexpr f f1 ;
//const f f1 ; // This also has the same issue
//constexpr f f1 = {} ; //This works
}
clang和gcc不同意它是否有效,clang提供以下诊断( see it live ):
error: default initialization of an object of const type 'const f' without a user-provided default constructor
constexpr f f1 ;
^
{}
据我所知,f
是一个文字类型,它由隐式默认构造函数初始化,它应该允许它被声明为constexpr。谁在这里是对的?
注意,如果我明确添加constexpr默认构造函数,则clang会接受f1
的声明:
constexpr f() {} ;
答案更改f
是否不是聚合?
答案 0 :(得分:7)
如果我们从草案C ++ 14标准部分7.1.5
[dcl.constexpr] 开始,我们可以找到constexpr对象声明的要求:
对象声明中使用的constexpr说明符将对象声明为const。这样的对象应该有 字面类型,应初始化。如果它是由构造函数调用初始化的,那么该调用应该是一个常量表达式(5.19)。
f
是文字类型吗?
第3.9
[basic.types] 部分说:
类型是文字类型,如果它是:
并涵盖以下项目中的课程:
具有以下所有属性的类类型(第9条)
- 它有一个简单的析构函数,
- 它是聚合类型(8.5.1)或至少有一个constexpr构造函数或构造函数模板 这不是复制或移动构造函数,
- 它的所有非静态数据成员和基类都是非易失性文字类型。
所以我们对第一和第三个子弹没问题。为了涵盖第二个项目符号,我们可以注意到f
是聚合但是如果我们稍微修改一下这个例子,例如f
看起来像这样:
struct f {
private:
int x = 0 ;
} ;
它不是C ++ 11或C ++ 14中的聚合,但问题仍然存在。然后我们需要证明它有一个constexpr构造函数。 f
是否有constexpr构造函数?
据我所知,第12.1
段 [class.ctor] 表示是:
[...]如果用户编写的默认构造函数满足constexpr构造函数(7.1.5)的要求, 隐式定义的默认构造函数是constexpr。 [...]
但遗憾的是,我们要求8.5
部分提供用户提供的构造函数,其中包含:
如果程序要求对const限定类型T的对象进行默认初始化,则T应为类类型 使用用户提供的默认构造函数。
所以看起来clang在这里是正确的,如果我们查看以下clang bug报告:"error: default initialization of an object of const type 'const Z' requires a user-provided default constructor" even when no constructor needed。因为defect report 253目前没有提议的措辞,并且它说(强调我的),所以clang基于他们缺乏对此的支持:
8.5 [dcl.init]第9段说:
如果没有为对象指定初始化程序,并且该对象是 (可能是cv限定的)非POD类类型(或其数组),. 对象应默认初始化; 如果对象是 const-qualified类型,底层类类型应具有 用户声明的默认构造函数。否则,如果没有初始化器 为对象指定,该对象及其子对象(如果有)具有 不确定的初始值;如果对象或其任何子对象 属于const限定类型,程序格式错误。
如果const POD对象没有非静态数据成员怎么办?这种措辞需要一个空的初始化器来处理这种情况
[...]
类似的注释适用于非POD const对象,其所有非静态数据成员和基类子对象都具有默认构造函数。为什么要求这样的对象的类具有用户声明的默认构造函数?
缺陷报告仍然开放,但最后一条评论说:
如果隐式默认构造函数初始化所有子对象,则不需要初始化程序。
还注意到:
应该根据constexpr构造函数和非静态数据成员初始化程序再次提出此问题。
请注意,自从出现缺陷报告以来,在8.5
部分中对const限定类型的约束进行了移动。这是由于提案N2762: Not so Trivial Issues with Trivial是在C ++ 11之前。
虽然缺陷报告仍然是开放的,但鉴于constexpr更改和非静态数据成员初始化程序,它似乎不再是必要的限制。特别是考虑到constexpr构造函数的以下要求:
- 应初始化每个非变量非静态数据成员和基类子对象(12.6.2);