数组成员初始化用户定义的类型

时间:2012-12-14 20:54:32

标签: c++ constructor c++11

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的构造函数,析构函数。 我似乎需要一个move-constructor或copy-constructor来初始化数组,但这似乎是违反直觉的,因为我真正想要的只是就地构造。

如果我在2个成员a0和a1中拆分[2]并分别构造它们,它就有效。然而,这看起来很可疑。

2 个答案:

答案 0 :(得分:4)

在聚合(8.5.1)的 list-initialization (8.5.4p1)中,对聚合元素执行的初始化形式是copy-initialization(8.5.1p2),甚至如果初始化是 direct-list-initialization

  

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

然而,仅仅因为执行初始化的形式是复制初始化并不意味着发生了复制。根据{{​​3}}, copy-list-initialization 应该与 direct-list-initialization 相同,但不允许使用显式构造函数。

答案 1 :(得分:2)

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

  

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

第8.5.1节/ 2:

  

当初始化程序列表初始化聚合时,如8.5.4中所述,初始化程序列表的元素将作为聚合成员的初始化程序,增加下标或成员顺序。 每个成员都是从相应的初始化子句中复制初始化的。 ...

(强调我的。)

此外,如果存在用户声明的复制构造函数,则编译器不会隐式生成移动构造函数(§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;
}

<子> Online demo

这与你想要的一样接近。