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からコピー初期化されます。

ただし、実行される初期化の形式がコピー初期化であるからといって、コピーが発生するわけではありません。copy-list-initialization of non-copyable typesに従って、copy-list-initializationは、明示的なコンストラクターが許可されていないことを除いて、direct-list-initializationと同じである必要があります。

于 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 に答える