51

当我运行此代码时:

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’

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

4

4 回答 4

56

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

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

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

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

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

当聚合由初始化列表初始化时,如 8.5.4 中所指定,初始化列表的元素被视为聚合成员的初始化,按递增的下标或成员顺序。每个成员都是从相应的初始化子句复制初始化的。如果 initializer-clause 是一个表达式并且需要一个窄化转换 (8.5.4) 来转换该表达式,则程序是非良构的。

当您这样做时X x = {0},聚合初始化用于初始化a0. 但是,当您这样做时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 的编译器即可。

于 2013-06-07T12:16:33.287 回答
4

使用 C++17 及更高版本,您可以大括号初始化您的派生结构。

您的代码现在可以编译(GodBolt)。

您确实会收到有关使用大括号的警告。因此,初始化 a 的推荐方法Y是:

Y y = { {0} };

而不是;

Y y = { 0 };

这是因为这种继承结构现在被认为是“聚合类型”(支持这种类型的聚合初始化)。请参阅2015 年的这篇论文

于 2020-09-18T19:38:57.390 回答
1

这个问题仍然在谷歌搜索结果中,所以我会在这里说。在 C++17 中是可能的。只有无构造器,无虚拟,无私有/受保护,但对于派生的 PODS,现在是可能的。

注意:今年(2021)eclipse for STM32(CubeIDE)仍然不提供c++17的菜单选择,但可以手动设置,例如-std=gnu++17

于 2021-09-08T08:46:42.210 回答
0

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};
    };
于 2021-11-20T22:34:44.820 回答