以下のコードをコンパイルすると、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ではエラーが発生しません。
標準ライブラリの他のコンテナとは異なり、std::array
は集約およびPODであるため、追加の中括弧が必要です。 std::array
にはユーザー定義のコンストラクターがありません。その最初のデータメンバーはサイズN
(テンプレート引数として渡す)の配列であり、このメンバーは初期化子で直接初期化されます。直接初期化されるinternal配列には、追加の中括弧が必要です。
状況は次と同じです。
//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」の初期化子が多すぎます
これは、std::array
(GCCを使用している場合)の場合に発生する同じエラーです。
したがって、正しいことは、次のように中括弧を使用することです。
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
};
which 正常にコンパイルされます 。繰り返しになりますが、internal配列を初期化しているため、追加の中括弧が必要です。
-
さて、問題は、double
の場合、なぜ余分な中括弧が必要ないのかということです。
これは、double
が集計ではなく、A
が集計であるためです。つまり、std::array<double, 2>
は集合体の集合体であり、std::array<A, 2>
は集合体の集合体です。1。
1. doubleの場合も( this のように)標準に完全に準拠するために追加の括弧が必要だと思いますが、コードはそれらがなくても機能します。もう一度スペックを掘り下げる必要があるようです!。
スペックを掘り下げました。このセクション(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行はy[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[0]
の初期化子はそうではないため、リストの3つの要素が使用されます。同様に、次の3つはy[1]
と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}
};
中括弧が省略されておらず、完全に中括弧で囲まれた初期化に十分な中括弧もありません。したがって、それは不正な形式です。