C++11默认的类成员初始化与初始化列表同时使用

7

请问有人能指出C++标准中相应的段落,或者可以解释一下为什么如果我取消注释({123}),我的代码就无法编译吗?

一般来说,我理解默认成员初始化和通过初始化列表进行初始化的使用方法存在问题,但我无法引用确切的原因。

enum class MY: int
{
    A = 1
};

struct abc
{
    int a;/*{123};*/  //compilation failed if uncommented
    MY m;
};

abc a = {1, MY::A};

如果出现未注释的文本,则会出现编译错误:

错误:无法将“{1,A}”从“<brace-enclosed initializer list>”转换为“abc”


1
在C++11中,使用NSDMI会使您的结构体不再是聚合体。我记得在C++14中这个已经改变了。 - Piotr Skotnicki
是的,如果你使用 -std=c++14 编译,那么就没问题了。 - Mine
如果是这种情况,那就值得另一个答案了! - underscore_d
1个回答

5
下面的语法:
abc a = {1, MY::A};

这是一种列表初始化方式,其行为取决于被初始化的类型。没有非静态数据成员初始化器(/*{123};*/),你的结构体是一个聚合体,此情况属于[dcl.init.list]/p3:

  • 否则,如果T是聚合体,则执行聚合初始化。

然而,在C++11中,要成为聚合体类型,必须满足以下条件:

聚合体是一个数组或一个类(Clause 9),没有用户提供的构造函数(12.1),非静态数据成员没有花括号或等号初始化器(9.2),没有私有或保护的非静态数据成员(Clause 11),没有基类(Clause 10),也没有虚函数(10.3)。

也就是说,使用NSDMI(非静态数据成员初始化)打破了上述一系列规则,因此,该类型的实例不再能够进行列表初始化。

这条规则在C++14中有所改变,当前的措辞为[dcl.init.aggr]/p1
聚合体是一个数组或者一个类,满足以下条件:
  • (1.1) 没有用户提供的、显式的或继承的构造函数([class.ctor]),

  • (1.2) 没有非静态的私有或保护数据成员([class.access]),

  • (1.3) 没有虚函数,

  • (1.4) 没有虚的、私有的或保护的基类([class.mi])。

[注:聚合初始化不允许访问受保护和私有基类的成员或构造函数。--end note]


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接