【问题标题】:Why doesn't Constructor/virtual destructor with braced initializer list work?为什么带有大括号初始值设定项列表的构造函数/虚拟析构函数不起作用?
【发布时间】:2017-11-30 15:42:30
【问题描述】:

为什么下面的代码不能编译?

#include <vector>

class Foo
{
public:
    Foo()
    { }

    virtual ~Foo()
    { }

    std::vector<int> aVec;
};


Foo bar =
{
    { 1, 2, 3, 4, 5 }
};

当以下代码编译时:

#include <vector>

class Foo
{
public:

    /*Foo()
    { }

    virtual*/ ~Foo()
    { }

    std::vector<int> aVec;
};


Foo bar =
{
    { 1, 2, 3, 4, 5 }
};

除了提及语言规则,请详细说明这些规则背后的基本原理。

为什么构造函数和虚析构函数的存在停止初始化?

【问题讨论】:

  • 当询问编译错误时,请包括编译错误。
  • 你是否试图忽略类构造函数?

标签: c++ constructor virtual-destructor


【解决方案1】:

因为Foo 是类类型,所以花括号初始化列表被视为aggregate initialization。除其他外,这要求该类没有显式构造函数或虚拟成员:

聚合初始化是列表初始化的一种形式,它 初始化聚合。聚合是以下类型之一:

类类型(通常是结构或联合),具有...

  • 没有私有或受保护的非静态数据成员

  • 没有用户提供的、继承的或显式(C++17 起)的构造函数(允许显式默认或删除的构造函数)

  • 没有虚拟、私有或受保护的基类
  • 没有虚拟成员函数
  • 默认成员初始化器

【讨论】:

    【解决方案2】:

    您使用的列表初始化形式称为aggregate initialization。它用于聚合类型。类型符合聚合条件的要求之一是它没有用户提供的构造函数。

    通过提供构造函数,编译器将尝试将列表初始化与定义的构造函数之一匹配。它将更喜欢采用单个std::initializer_list 的构造函数。由于您没有提供一个,它会尝试找到一个构造函数,其参数与您的初始化列表提供的参数匹配。由于唯一的构造函数是不带参数的默认构造函数,因此找不到匹配项。

    【讨论】:

      【解决方案3】:

      Foo bar = { { 1, 2, 3, 4, 5 } };aggregate initialization。它只为数组和“聚合”类类型定义。添加任何构造函数或虚拟成员意味着该类型不是聚合的。

      【讨论】:

        最近更新 更多