当我运行这段代码时:
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’
为什么花括号初始化对基类有效,而对派生类无效?
当我运行这段代码时:
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’
为什么花括号初始化对基类有效,而对派生类无效?
C++17之前的标准版本的回答:
您的问题与聚合初始化有关: struct X
是一个聚合体,而struct Y
不是。以下是关于聚合体(8.5.1)的标准引用:
聚合体是数组或没有用户提供的构造函数(12.1),非静态数据成员没有大括号或等于符号初始化程序(9.2),没有私有或受保护非静态数据成员(第11条),没有基类(第10条)和没有虚拟函数(10.3)的类(第9条)。
该条款规定了如果一个类具有基类,则它不是聚合体。在这里,struct Y
将struct X
作为基类,因此不能是聚合类型。
关于您所遇到的特定问题,请参阅标准中的以下条款:
当使用初始化程序列表初始化聚合体时,如8.5.4中所指定,初始化程序列表的元素按递增的下标或成员顺序作为聚合体的成员的初始值。每个成员从相应的初始化程序子句中进行复制初始化。如果初始化程序子句是表达式并需要缩小转换(8.5.4)来转换表达式,则程序无法形成。
当您执行X x = {0}
时,使用聚合初始化将a
初始化为0
。但是,当您执行Y y = {0}
时,由于struct Y
不是聚合类型,编译器将查找适当的构造函数。由于隐式生成的构造函数(默认值,复制和移动)都不能对单个整数执行任何操作,因此编译器会拒绝您的代码。
关于这个构造函数查找,clang++的错误消息更加明确地说明了编译器实际上要做什么(在线示例):
Y Y = {0};
^ ~~~
main.cpp:5:8: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const Y &' for 1st argument
struct Y : public X {};
^
main.cpp:5:8: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'int' to 'Y &&' for 1st argument
struct Y : public X {};
^
main.cpp:5:8: note: candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided
请注意,有一个提案来扩展聚合初始化以支持您的用例,并且它已经被纳入C++17。如果我理解正确,它使您的示例具有您期望的语义有效。因此...您只需等待符合C++17的编译器。
在C++14及更低版本中,构造函数应该使用默认初始化。
struct Base
{
int member1{-54};
std::string member2{"Base"};
};
struct OtherType : Base
{
OtherType = default;
OtherType(int i,std::string s, int j) : Base{i,s}, member3{j} {}
int member3{5};
};
int main()
{
OtherType ot{ 45, "other", 13} ;
OtherType ot = { 13, "heynow", -1};
OtherType ot;
std::cout << "{" << ot.member1
<< ", " << ot.member2
<< ", " << ot.member3 << "}\n";
return 0;
}
C++17 -20 最适合的用途是:
struct Base
{
int member1{-54};
std::string member2{"Base"};
};
struct OtherType : Base
{
int member3{5};
};
clang++ -std=c++1z
版本 4.0.1 可以编译,g++ -std=c++17
版本 7.2.1 可以编译, 但是 Visual Studio 2017 的cl
版本 19.12.25816 还不能。 - Patrick Fromberg