是一个空类可用作没有初始化或显式默认构造函数的constexpr变量? [英] Is an empty class usable as a constexpr variable without an intializer or explicit default constructor?

查看:1555
本文介绍了是一个空类可用作没有初始化或显式默认构造函数的constexpr变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出以下代码:

  struct f {
}

int main(){
constexpr f f1;
// const f f1; //这也有相同的问题
// constexpr f f1 = {}; // This works
}

clang和gcc不同意它是否有效提供以下诊断信息( 查看实时 ):

 错误:没有用户提供的默认构造函数的const类型const f的对象的默认初始化
constexpr f f1;
^
{}

至于我可以告诉 f 是一个文字类型,它由隐式默认的构造函数初始化,它应该允许它被声明为constexpr。这里是谁是正确的?



注意,如果我明确添加一个constexpr默认构造函数,clang接受 f1 的声明:

  constexpr f(){}; 

答案变化是 f 如果我们从草案C ++ 14标准部分开始 7.1.5

[dcl.constexpr] 我们可以找到一个constexpr对象声明的要求是:


在对象声明中使用的constexpr说明符将对象声明为const。这样的对象应该有
字面类型,并且应该初始化。如果它是由构造函数调用初始化的,那么该调用将是一个常量表达式(5.19)。


> f 是一个文字类型?



3.9 类型] 说:


如果是:


< blockquote>

并覆盖以下项目中的课程:



  • 具有以下所有属性的类类型(第9条)




    • 它有一个简单的析构函数,

    • 它是一个聚合类型(8.5.1)或至少有一个constexpr构造函数或构造函数模板
      不是复制或移动构造函数,

    • 所有非静态数据成员和基类都是非挥发性的字面类型。



< blockquote>

所以我们可以在第一和第三个项目符号。为了覆盖第二个项目符号,我们可以注意到 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错误报告:错误:const类型的对象的默认初始化'const Z'需要一个用户提供的默认构造函数,即使不需要构造函数。因此,俚语由于缺乏对此的支持,因为缺陷报告253 ,它目前没有建议的措辞,并说(强调我):


8.5 [dcl.init]的第9段说:


如果没有为某个对象指定初始值设定项, $ b(可能是cv限定的)非POD类类型(或其数组),
对象应被默认初始化; 如果对象是
const限定类型,基础类类型应具有
用户声明的默认构造函数
。否则,如果没有为对象指定
,则对象及其子对象(如果有)具有不确定的初始值
;如果对象或其任何子对象
是const限定类型,则程序未生成


如果const POD对象没有非静态数据成员,该怎么办?



类似的注释适用于非法的-POD const对象,其所有非静态数据成员和基类子对象都有默认构造函数。为什么这样一个对象的类需要有一个用户声明的默认构造函数?


缺陷报告仍然打开,但是最后一个注释说:


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


并注意:


constexpr构造函数和非静态数据成员初始化器的光。


请注意 8.5 部分中的const限定类型的约束缺陷报告来了。这是由于投标 N2762:不是这样的小问题with the trivial that is pre C ++ 11.



虽然缺陷报告仍然打开,给定constexpr更改和非静态数据成员初始化器似乎不再是必要的限制。特别是考虑以下对constexpr构造函数的要求:



  • 每个非变体非静态数据成员和基类子对象应初始化(12.6.2);



Given the following code:

struct f {
};

int main(){
    constexpr f f1 ;
    //const f f1  ; // This also has the same issue
    //constexpr f f1 = {} ; //This works
}

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 ;
            ^
              {}

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?

Note, clang does accept the declaration of f1 if I explicitly add a constexpr default constructor:

constexpr f() {} ;

Does the answer change is f is not an aggregate?

解决方案

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:

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).

So is f is a literal type?

Section 3.9 [basic.types] says:

A type is a literal type if it is:

and covers classes in the following bullet:

  • a class type (Clause 9) that has all of the following properties

    • 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.

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 ;
} ;

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?

As far as I can tell section 12.1 [class.ctor] says yes:

[...] If that user-written default constructor would satisfy the requirements of a constexpr constructor (7.1.5), the implicitly-defined default constructor is constexpr. [...]

But we are unfortunately required to have a user-provided constructor by section 8.5 which says:

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.

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):

Paragraph 9 of 8.5 [dcl.init] says:

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.

What if a const POD object has no non-static data members? This wording requires an empty initializer for such cases

[...]

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.

and also notes:

This issue should be brought up again in light of constexpr constructors and non-static data member initializers.

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.

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:

  • every non-variant non-static data member and base class sub-object shall be initialized (12.6.2);

这篇关于是一个空类可用作没有初始化或显式默认构造函数的constexpr变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆