空类是否可用作没有初始化程序或显式默认构造函数的constexpr变量? [英] Is an empty class usable as a constexpr variable without an initializer or explicit default constructor?
问题描述
给出以下代码:
struct f {
};
int main(){
constexpr f f1 ;
//const f f1 ; // This also has the same issue
//constexpr f f1 = {} ; //This works
}
clang和gcc在是否有效上存在分歧,clang提供了以下诊断信息( 请参见直播 ):
clang and gcc disagree over whether it is valid, with clang providing the following diagnostic (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.谁是对的?
As far as I can tell f
is a literal type and it is initialized by the implicitly defaulted constructor which should allow it to be declared constexpr. Who is correct here?
注意,如果我显式添加constexpr默认构造函数,则clang确实接受f1
的声明:
Note, clang does accept the declaration of f1
if I explicitly add a constexpr default constructor:
constexpr f() {} ;
答案是否更改为f
不是汇总?
Does the answer change is f
is not an aggregate?
推荐答案
如果我们从C ++ 14标准草案草案7.1.5
[dcl.constexpr] 开始,我们可以找到以下要求: constexpr对象声明为:
If we start from the draft C++14 standard section 7.1.5
[dcl.constexpr] we can find the requirements for a constexpr object declaration are:
在对象声明中使用的constexpr说明符将该对象声明为const.此类物体应具有 文字类型,应进行初始化.如果它是通过构造函数调用初始化的,则该调用应为常量表达式(5.19).
A constexpr specifier used in an object declaration declares the object as const. Such an object shall have literal type and shall be initialized. If it is initialized by a constructor call, that call shall be a constant expression (5.19).
f
是文字类型吗?
部分3.9
[基本类型] 说:
如果是,则类型为文字类型
A type is a literal type if it is:
并在以下项目符号中介绍了这些类:
and covers classes in the following bullet:
具有以下所有属性的类类型(第9条)
a class type (Clause 9) that has all of the following properties
- 它有一个琐碎的析构函数,
- 它是聚合类型(8.5.1)或具有至少一个constexpr构造函数或构造函数模板 不是复制或移动构造函数,并且
- 其所有非静态数据成员和基类均为非易失性文字类型.
- it has a trivial destructor,
- it is an aggregate type (8.5.1) or has at least one constexpr constructor or constructor template that is not a copy or move constructor, and
- all of its non-static data members and base classes are of non-volatile literal types.
所以我们对第一个和第三个项目符号表示满意.为了覆盖第二个项目符号,我们可以注意到f
是 aggregate ,但是如果我们稍微修改示例,例如f
看起来像这样:
So we are okay on the first and third bullet. To cover the second bullet, we could note that f
is an aggregate but if we modify the example slightly, for example if f
looked like this:
struct f {
private:
int x = 0 ;
} ;
在C ++ 11或C ++ 14中都不是合计的,但问题仍然存在.然后,我们需要显示它具有constexpr构造函数. f
是否具有constexpr构造函数?
which would not be an aggregate in either C++11 or C++14 but the issue would still exist. Then we need to show it has a constexpr constructor. Does f
have a constexpr constructor?
据我所知,12.1
[class.ctor] 是:
[...]如果该用户编写的默认构造函数将满足constexpr构造函数(7.1.5)的要求, 隐式定义的默认构造函数为constexpr. [...]
[...] If that user-written default constructor would satisfy the requirements of a constexpr constructor (7.1.5), the implicitly-defined default constructor is constexpr. [...]
但是很遗憾,我们必须在8.5
部分中要求用户提供构造函数,
But we are unfortunately required to have a user-provided constructor by section 8.5
which says:
如果程序要求对const限定类型T的对象进行默认初始化,则T应为类类型 使用用户提供的默认构造函数.
If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.
因此,如果我们查看以下clang错误报告,那么clang似乎是正确的:错误:const类型'const Z'的对象的默认初始化需要用户提供的默认构造函数",即使不需要构造函数也是如此.因此,由于报告253 ,目前尚无建议的措词,并说(强调我的):
So it looks like clang is correct here and if we look at the following clang bug report: "error: default initialization of an object of const type 'const Z' requires a user-provided default constructor" even when no constructor needed. So clang is basing their lack of support for this due to defect report 253 which does not currently have a proposed wording and it says (emphasis mine):
8.5 [dcl.init]第9段说:
Paragraph 9 of 8.5 [dcl.init] says:
如果未为对象指定初始化程序,并且该对象属于 (可能具有CV资格)非POD类类型(或其数组), 对象应被默认初始化; 如果对象是 const限定类型,基础类类型应具有 用户声明的默认构造函数.否则,如果没有初始化程序,则为 为对象指定的,该对象及其子对象(如果有)具有 不确定的初始值;如果对象或其任何子对象 属于const限定类型,程序格式错误.
If no initializer is specified for an object, and the object is of (possibly cv-qualified) non-POD class type (or array thereof), the object shall be default-initialized; if the object is of const-qualified type, the underlying class type shall have a user-declared default constructor. Otherwise, if no initializer is specified for an object, the object and its subobjects, if any, have an indeterminate initial value; if the object or any of its subobjects are of const-qualified type, the program is ill-formed.
如果const POD对象没有非静态数据成员该怎么办?在这种情况下,这种措词需要一个空的初始化程序
What if a const POD object has no non-static data members? This wording requires an empty initializer for such cases
[...]
类似的注释适用于非POD const对象,其所有非静态数据成员和基类子对象均具有默认构造函数.为什么要要求此类对象的类具有用户声明的默认构造函数?
Similar comments apply to a non-POD const object, all of whose non-static data members and base class subobjects have default constructors. Why should the class of such an object be required to have a user-declared default constructor?
缺陷报告仍处于打开状态,但最后的评论是:
The defect report is still open but the last comment on it says:
如果隐式默认构造函数初始化所有子对象,则不需要初始化程序.
If the implicit default constructor initializes all subobjects, no initializer should be required.
并注意:
应该根据constexpr构造函数和非静态数据成员初始化程序再次提出此问题.
This issue should be brought up again in light of constexpr constructors and non-static data member initializers.
请注意,自缺陷报告发布以来,在8.5
节中四处移动的const限定类型的约束.这是由于提案 N2762:并非如此琐碎的问题是在C ++ 11之前的Trivial 中实现的.
Note the constraints on const qualified types moved around in section 8.5
since the defect report came about. This was due to proposal N2762: Not so Trivial Issues with Trivial which was pre C++11.
尽管缺陷报告仍处于打开状态,但鉴于constexpr更改和非静态数据成员初始化程序,它似乎不再是必要的限制.尤其要考虑对constexpr构造函数的以下要求:
Although the defect report is still open, given the constexpr changes and non-static data member initializers it does not seem like a necessary restriction anymore. Especially considering the following requirement on a constexpr constructor:
- 每个不变的非静态数据成员和基类子对象都应初始化(12.6.2);
- every non-variant non-static data member and base class sub-object shall be initialized (12.6.2);
这篇关于空类是否可用作没有初始化程序或显式默认构造函数的constexpr变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!