51

以下のコードをコンパイルすると、VC2010 でエラー C2078 が発生します。

struct A
  {
  int foo;
  double bar;
  };

std::array<A, 2> a1 = 
  // error C2078: too many initializers
  {
    {0, 0.1},
    {2, 3.4}
  };

// OK
std::array<double, 2> a2 = {0.1, 2.3};

の正しい構文a1

std::array<A, 2> a1 = 
  {{
    {0, 0.1},
    {2, 3.4}
  }};

問題は、なぜ追加のブレースが必要なa1のに不要なのa2かということです。

アップデート

質問は std::array に固有のものではないようです。いくつかの例:

struct B
  {
  int foo[2];
  };

// OK
B meow1 = {1,2};
B bark1 = {{1,2}};

struct C
  {
  struct 
    { 
    int a, b; 
    } foo;
  };

// OK
C meow2 = {1,2};
C bark2 = {{1,2}};

struct D
  {
  struct 
    { 
    int a, b; 
    } foo[2];
  };

D meow3 = {{1,2},{3,4}};  // error C2078: too many initializers
D bark3 = {{{1,2},{3,4}}};

struct Dエラーが発生する理由はまだわかりませんが、BとCは発生しません。

4

1 に答える 1

66

std::array標準ライブラリの他のコンテナとは異なり、 は集約と POD であるため、余分な中括弧が必要です。std::arrayユーザー定義のコンストラクターがありません。その最初のデータ メンバーはサイズの配列N(テンプレート引数として渡す) であり、このメンバーは初期化子で直接初期化されます。直接初期化される内部配列には追加の中かっこが必要です。

状況は次と同じです。

//define this aggregate - no user-defined constructor
struct Aarray
{
   A data[2];  //data is an internal array
};

これをどのように初期化しますか?これを行う場合:

Aarray a1 =
{
   {0, 0.1},
   {2, 3.4}
};

コンパイルエラーが発生します:

エラー: 'Aarray' の初期化子が多すぎます

これは、(GCC を使用している場合) の場合に発生するエラーと同じです。std::array

したがって、正しいことは、次のようにブレースを使用することです。

Aarray a1 =
{
  {  //<--this tells the compiler that initialization of `data` starts

        { //<-- initialization of `data[0]` starts

           0, 0.1

        }, //<-- initialization of `data[0]` ends

       {2, 3.4}  //initialization of data[1] starts and ends, as above

  } //<--this tells the compiler that initialization of `data` ends
};

これは正常にコンパイルされます。ここでも、内部配列を初期化しているため、追加の中かっこが必要です。

--

問題は、次の場合に追加のブレースが必要ない理由doubleです。

double集合体ではないからAです。つまり、std::array<double, 2>は集計の集計であり、std::array<A, 2>は集計の集計の集計1です。

1.標準に完全に準拠するために、 double の場合も (このように) 追加の中括弧が必要だと思いますが、コードはそれらがなくても機能します。仕様をもう一度掘り下げる必要があるようです。.

ブレースと追加のブレースの詳細

スペックを掘り下げました。このセクション (C++11 の §8.5.1/11) は興味深いもので、このケースに適用されます。

フォームの宣言で

T x = { a };

中括弧は、次のように初期化リストで省略できます。初期化子リストが左中括弧で始まる場合、後続の初期化子句のコンマ区切りリストは、サブ集約のメンバーを初期化します。メンバーより多くの初期化句があるのは誤りです。ただし、部分集合体の初期化リストが左中括弧で始まらない場合、部分集合体のメンバーを初期化するのに十分なだけの初期化句がリストから取得されます。残りの初期化句は、現在のサブ集約がメンバーである集約の次のメンバーを初期化するために残されます。[ 例:

float y[4][3] = {
{ 1, 3, 5 },
{ 2, 4, 6 },
{ 3, 5, 7 },
};

1、3、および 5 は、配列 の最初の行y[0]、つまりy[0][0]y[0][1]、およびを初期化しy[0][2]ます。同様に、次の 2 行で initializey[1]y[2]. 初期化子は早期に終了するため、y[3]s要素は float() 形式の式で明示的に初期化されたかのように初期化されます。つまり、0.0 で初期化されます。次の例では、initializer-list の中括弧が省略されています。ただし、initializer-list は、上記の例の完全に括弧付きの initializer-list と同じ効果があります。

float y[4][3] = {
1, 3, 5, 2, 4, 6, 3, 5, 7
};

y のイニシャライザは左中かっこで始まりますが、y のイニシャライザはそうでy[0]はないため、リストの 3 つの要素が使用されます。y[1]同様に、次の 3 つはとに対して連続して取得されy[2]ます。—終わりの例]

上記の引用から私が理解したことに基づいて、次のことが許可されるべきであると言えます。

//OKAY. Braces are completely elided for the inner-aggregate
std::array<A, 2> X =   
{
  0, 0.1,
  2, 3.4
};

//OKAY. Completely-braced initialization
std::array<A, 2> Y = 
{{
   {0, 0.1},
   {2, 3.4}
}};

最初のものでは、内部集約のブレースが完全に省略されていますが、2 番目のものでは初期化が完全にブレースされています。あなたの場合(の場合)、初期化は最初のアプローチを使用します(内側の集約ではdouble中括弧は完全に省略されています)。

しかし、これは許可されるべきではありません:

//ILL-FORMED : neither braces-elided, nor fully-braced
std::array<A, 2> Z = 
{
  {0, 0.1},
  {2, 3.4}
};

中かっこが省略されているわけでも、完全に中かっこを初期化するのに十分な中かっこがないわけでもありません。したがって、それは不適切な形式です。

于 2012-07-31T07:18:35.877 に答える