C++ 为什么我不能初始化从另一个结构派生的结构?

C++ 为什么我不能初始化从另一个结构派生的结构?,c++,c++11,struct,list-initialization,C++,C++11,Struct,List Initialization,当我运行此代码时: struct X { int a; }; struct Y : public X {}; X x = {0}; Y Y = {0}; 我得到: error: could not convert ‘{0}’ from ‘<brace-enclosed initializer list>’ to ‘Y’ 错误:无法将“{0}”从“”转换为“Y” 为什么大括号初始化对基类有效而对派生类无效?您的问题与:struct X是聚合,而struct Y不是聚合

当我运行此代码时:

struct X {
    int a;
};

struct Y : public X {};

X x = {0};
Y Y = {0};
我得到:

error: could not convert ‘{0}’ from ‘<brace-enclosed initializer list>’ to ‘Y’
错误:无法将“{0}”从“”转换为“Y”

为什么大括号初始化对基类有效而对派生类无效?

您的问题与:
struct X
是聚合,而
struct Y
不是聚合有关。以下是有关骨料的标准报价(8.5.1):

聚合是一个数组或类(第9条),没有用户提供的构造函数(12.1),没有用于非静态数据成员的大括号或等效初始值设定项(9.2),没有私有或受保护的非静态数据成员(第11条),没有基类(第10条),也没有虚拟函数(10.3)

此子句指定如果
具有基类,则它不是聚合。这里,
struct Y
struct X
作为基类,因此不能是聚合类型

关于您遇到的特定问题,请从标准中选取以下条款:

当聚合由初始值设定项列表初始化时,如8.5.4所述,初始值设定项列表中的元素被视为聚合成员的初始值设定项,下标或成员顺序递增。每个成员都是从相应的初始值设定项子句复制初始化的。如果初始值设定项子句是一个表达式,并且需要进行缩小转换(8.5.4)来转换该表达式,则程序的格式不正确

执行
X={0}
时,聚合初始化用于将
a
初始化为
0
。但是,当您执行
Y={0}
时,由于
struct Y
不是聚合类型,编译器将查找适当的构造函数。由于隐式生成的构造函数(default、copy和move)都不能处理单个整数,因此编译器拒绝您的代码


关于这个构造函数查找,来自clang++的错误消息对于编译器实际要做的事情更加明确了一点():


请注意,需要扩展聚合初始化以支持您的用例,并将其转换为C++17。如果我读对了,它将使您的示例具有您期望的语义。所以您只需等待与C++17兼容的编译器。

使用C++17及更高版本,您可以初始化派生结构。 你的代码现在(GodBolt)

你会收到关于使用分支的警告。因此,建议初始化
Y
的方法是:

Y y = { {0} };
而不是

Y y = { 0 };

这是因为这样的继承结构现在被认为是“聚合类型”(允许聚合初始化)。请参见2015年版。

clang++-std=c++1z
4.0.1版已编译,
g++-std=c++17版已编译,但Visual Studio 2017
cl
19.12.25816版自今年夏天开始不应该是VS 2017 15.7版
Y y = { 0 };