为什么我不能大括号初始化从另一个结构派生的结构?

新手上路,请多包涵

当我运行此代码时:

 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’

为什么大括号初始化适用于基类而不适用于派生类?

原文由 Eric 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 700
1 个回答

C++ 17 之前的 C++ 标准版本的答案:

您的问题与 聚合初始化 有关: struct X 是聚合,而 struct Y 不是。这是关于聚合的标准报价(8.5.1):

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

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

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

当聚合由初始化列表初始化时,如 8.5.4 中所指定,初始化列表的元素被视为聚合成员的初始化,按递增的下标或成员顺序。每个成员都是从相应的初始化子句复制初始化的。如果 initializer-clause 是一个表达式并且需要一个窄化转换 (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 的编译器即可。

原文由 Morwenn 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏