6

g++ 4.7 支持数组成员初始化,我开始使用它。

下面的代码无法编译。

struct A
{
   A(int){};
   A(const A&) = delete;
   A& operator=(const A&) = delete;
   ~A(){};
};

struct B
{
   B():
      a{{0},{1}}
   {};
   A a[2];
};

B b;

gcc 4.8(预发行版)的错误消息是:

n.cc: In constructor ‘B::B()’:
n.cc:12:20: error: use of deleted function ‘A::A(const A&)’
           a{{0},{1}}
             ^
n.cc:4:8: error: declared here
        A(const A&) = delete;
        ^

有没有办法让这段代码工作?我不能轻易更改 A 的构造函数和析构函数。我似乎需要一个移动构造函数或复制构造函数来初始化数组,但这似乎违反直觉,因为我真正想要的只是就地构造。

如果我将 a[2] 拆分为 2 个成员 a0 和 a1,并分别构造它们,它会起作用。然而,这看起来很可疑。

4

2 回答 2

4

在聚合 (8.5.1) 的列表初始化(8.5.4p1) 中,对聚合元素执行的初始化形式是复制初始化 (8.5.1p2),即使初始化是直接列表初始化

当聚合由初始化列表初始化时,如 8.5.4 中所指定,初始化列表的元素被视为聚合成员的初始化,按递增的下标或成员顺序。每个成员都是从相应的initializer-clause复制初始化的。

但是,仅仅因为执行的初始化形式是复制初始化,并不意味着发生了复制。根据不可复制类型的复制列表初始化,复制列表初始化应该与直接列表初始化相同,但不允许使用显式构造函数。

于 2012-12-14T21:21:46.373 回答
2

数组是聚合,聚合初始化总是使用复制初始化。C++11 §8.5.1/1:

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

§8.5.1/2:

当聚合由初始化列表初始化时,如 8.5.4 中所指定,初始化列表的元素被视为聚合成员的初始化,按递增的下标或成员顺序。每个成员都是从相应的initializer-clause复制初始化的。

(强调我的。)

此外,如果存在用户声明的复制构造函数,编译器不会隐式生成移动构造函数(第 12.8/9 节);因为您有一个定义为已删除的用户声明的复制构造函数,A它既没有复制也没有移动构造函数。显式添加移动构造函数有效:

struct A
{
   A(int) { }
   A(A const&) = delete;
   A& operator = (A const&) = delete;
   A(A&&) = default;
   ~A() = default;
};

struct B
{
   B() : a{{0}, {1}} { }
   A a[2];
};

int main()
{
   B b;
}

在线演示

这几乎与您想要的一样接近。

于 2012-12-14T21:12:06.430 回答