具有不可复制成员的类的聚合初始化

Aggregate initialization of class with noncopyable member

本文关键字:初始化 成员 可复制      更新时间:2023-10-16

假设我有一些删除复制构造函数的类:

struct NoCopy
{
    NoCopy(int) {}
    NoCopy(const NoCopy &) = delete;
};

我在另一个类中使用这个类:

struct Aggregate
{
    NoCopy nc;
};

但是当我尝试使用聚合初始化时

int main()
{
    Aggregate a{3};
}

编译器输出以下错误:

error: use of deleted function ‘NoCopy::NoCopy(const NoCopy&)’

为什么聚合初始化需要类成员的复制构造函数?聚合初始化是否使用复制构造函数初始化所有成员?

您想要的正确语法是:

Aggregate a{{3}};

这为 NoCopy 成员提供了一个初始值设定项。如果没有额外的{}编译器需要执行从 intNoCopy 的转换(它很高兴通过非显式构造函数执行此操作(,然后使用它来构造nc。 这通常作为移动构造发生,但通过删除复制 ctor,您也有效地删除了移动构造函数。

一种更简单的思考方法可能是想象NoCopy有一个值构造函数接受两个参数而不是一个参数:

struct NoCopy {
    NoCopy(int, int);
};

现在如果你写

Aggregate a{1, 2};

这将表明1用于初始化nc2用于初始化其他内容(编译时错误(。 您必须添加额外的{}才能有意义

Aggregate a{{1, 2}};

第三种方法涉及查看函数调用:

struct NoCopy {
  NoCopy(int) {}
  NoCopy(const NoCopy &) = delete;
};
void fun(NoCopy) { }
int main() {
  fun(1); // wrong
  fun({1}); // right
}

// wrong版本中,使用 NoCopy(int) 构造函数在调用站点构造临时NoCopy对象。然后临时通过值传递到fun,但由于NoCopy不可复制,所以失败。

// right版本中,您将为要用来构造的参数提供初始值设定项列表。不制作副本。