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 2017cl
19.12.25816版自今年夏天开始不应该是VS 2017 15.7版
Y y = { 0 };