Sha*_*our 9 c++ language-lawyer constexpr c++11 c++14
给出以下代码:
struct f {
};
int main(){
constexpr f f1 ;
//const f f1 ; // This also has the same issue
//constexpr f f1 = {} ; //This works
}
Run Code Online (Sandbox Code Playgroud)
clang和gcc不同意它是否有效,clang提供以下诊断(见现场直播):
error: default initialization of an object of const type 'const f' without a user-provided default constructor
constexpr f f1 ;
^
{}
Run Code Online (Sandbox Code Playgroud)
据我所知f,它是一个文字类型,它由隐式默认的构造函数初始化,它应该允许它被声明为constexpr.谁在这里是对的?
注意,f1如果我显式添加constexpr默认构造函数,则clang会接受声明:
constexpr f() {} ;
Run Code Online (Sandbox Code Playgroud)
答案变化f是不是聚合?
如果我们从草案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 ;
} ;
Run Code Online (Sandbox Code Playgroud)
它不会是C++ 11或C++ 14中的聚合,但问题仍然存在.然后我们需要证明它有一个constexpr构造函数.是否f有constexpr构造?
据我所知,12.1 [class.ctor]部分说是的:
[...]如果用户编写的默认构造函数满足constexpr构造函数(7.1.5)的要求,则隐式定义的默认构造函数为constexpr.[...]
但遗憾的是,我们需要按部分提供用户提供的构造函数,8.5其中说:
如果程序要求对const限定类型T的对象进行默认初始化,则T应为具有用户提供的默认构造函数的类类型.
所以看起来clang在这里是正确的,如果我们看下面的clang bug报告:"错误:const类型'const Z'对象的默认初始化需要用户提供的默认构造函数",即使没有构造函数需要.因此,由于缺陷报告253目前没有提议的措辞,并且它说(强调我的),因此clang基于他们缺乏对此的支持:
8.5 [dcl.init]第9段说:
如果没有为对象指定初始化程序,并且该对象是(可能是cv限定的)非POD类类型(或其数组),则该对象应默认初始化; 如果对象是const限定类型,则底层类类型应具有用户声明的默认构造函数.否则,如果没有为对象指定初始化程序,则该对象及其子对象(如果有)具有不确定的初始值; 如果对象或其任何子对象是const限定类型,则程序格式错误.
如果const POD对象没有非静态数据成员怎么办?这种措辞需要一个空的初始化器来处理这种情况
[...]
类似的注释适用于非POD const对象,其所有非静态数据成员和基类子对象都具有默认构造函数.为什么要求这样的对象的类具有用户声明的默认构造函数?
缺陷报告仍然开放,但最后一条评论说:
如果隐式默认构造函数初始化所有子对象,则不需要初始化程序.
并且还注意到:
应根据constexpr构造函数和非静态数据成员初始化程序再次提出此问题.
请注意,8.5自缺陷报告出现以来,对const限定类型的约束在部分中移动了.这是由于提案N2762:不是那么琐碎的问题,这是微不足道的 C++ 11之前的问题.
虽然缺陷报告仍然是开放的,但鉴于constexpr更改和非静态数据成员初始化程序,它似乎不再是必要的限制.特别是考虑到constexpr构造函数的以下要求:
- 应初始化每个非变量非静态数据成员和基类子对象(12.6.2);