显式默认默认构造函数和聚合 [英] Explicit defaulted default constructor and aggregates

查看:59
本文介绍了显式默认默认构造函数和聚合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我编译以下代码的 #if 0 #if 1 版本时,如何解释差异:

  #include< cstdlib> 

结构体A
{
显式A()=默认值; //允许使用明确默认或删除的构造函数(自C ++ 11起)
#if 1
private:
#endif
int i;
};

int
main()
{
A a = {};
返回EXIT_SUCCESS;
}



  • 用于 #if 0 一切正常,编译成功。

  • 用于 #if 1 编译失败,并显示错误消息:
    < blockquote>

    错误:所选的构造函数在复制初始化中是显式的





表达式 A a = {}; 有什么区别,这取决于 A 是否加总?

解决方案

TL; DR:Clang和GCC在拒绝您的代码时出错。



但是,一旦您引入了私人成员,则必须按照红色框进行值初始化。因此,适用[dcl.init] /(8.2):





[dcl.init] /(7.1)定义了这种情况下的默认初始化:





第§13.3.1.3给出


对于[…]默认初始化,候选
函数是正在初始化
的对象类的所有构造函数。


考虑原始上下文-复制或直接初始化。 (第13.3.1.7节也不适用。)实际上,这是故意的;参见> CWG#1518


此问题通过问题1630 默认初始化现在使用13.3.1.3 [over.match.ctor],现在允许


Clang和GCC(和VC ++)尚未实现相应的DR,并且因此,在C ++ 14模式下拒绝代码是不正确的。






1)
您的班级有一个用户声明的构造函数,但它不是用户提供的 ,即不妨碍您的班级成为聚合类。回忆一下[dcl.init.aggr] / 1中的定义:


aggregate 是一个数组或一个类(第9条),没有用户提供的
构造函数(12.1),没有私有或受保护的非静态数据成员
(第11条),没有基类(第10条),也没有虚拟函数
(10.3)。



How to explain the difference, when I compile #if 0 and #if 1 versions of the following code:

#include <cstdlib>

struct A
{ 
    explicit A() = default; // explicitly defaulted or deleted constructors are allowed for aggregates (since C++11)
#if 1
private :
#endif
    int i;
};

int
main()
{
    A a = {};
    return EXIT_SUCCESS;
}

  • for #if 0 all is fine, compilation successful.
  • for #if 1 compilation failed with error message:

    error: chosen constructor is explicit in copy-initialization

What is the difference for expression A a = {}; depending on whether A is aggreagate or not?

解决方案

TL;DR: Clang and GCC are wrong in rejecting your code. CWG 1630´s resolution made default-initialization well-formed regardless of the chosen default constructor being explicit or not.


In the variation of your code in which i is private, A is not an aggregate, as these cannot have private members. As long as i is public, however, A is an aggregate1, and no constructor is invoked since aggregate initialization is performed (see blue box), so your constructor being explicit is irrelevant.

However, as soon as you introduce the private member, you necessitate value-initialization as per the red box. Hence [dcl.init]/(8.2) applies:

[dcl.init]/(7.1) defines default-initialization for this case:

And §13.3.1.3 gives

For […] default-initialization, the candidate functions are all the constructors of the class of the object being initialized.

At no point is the original context - copy- or direct-initialization - considered. (§13.3.1.7 doesn't apply either.) In fact, this is intended; see CWG #1518:

This issue is resolved by the resolution of issue 1630: default initialization now uses 13.3.1.3 [over.match.ctor], which now permits explicit constructors for default-initialization.

Clang and GCC (and VC++) haven't implemented the corresponding DR yet and are thus incorrect in rejecting the code in C++14 mode.


1) Your class has a user-declared constructor, but it isn't user-provided, i.e. not impeding your class from being an aggregate. Recall the definition in [dcl.init.aggr]/1:

An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).

这篇关于显式默认默认构造函数和聚合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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