web-dev-qa-db-ja.com

std :: array初期化でのブレースの省略

初期化するstd::arrayがあるとします。二重中括弧を使用しても問題ありません。

std::array<int, 2> x = {{0, 1}};
std::array<int, 2> x{{0, 1}};

古き良き集計の初期化で単一の中括弧を使用することもできます。中括弧の省略によって欠落している中括弧が処理されるためです。

std::array<int, 2> x = {0, 1};

ただし、単一の中括弧でリストの初期化を使用しても大丈夫ですか? GCCはそれを受け入れ、Clangは「直接リスト初期化を使用する場合、サブオブジェクトの初期化を囲む中括弧を省略できない」と拒否します。

std::array<int, 2> x{0, 1};

ブレースの省略が言及されている標準の唯一の部分は8.5.1/12であり、次のように述べています。

代入式を使用して集約メンバーを初期化するときに、すべての暗黙的な型変換(句4)が考慮されます。代入式がメンバーを初期化できる場合、メンバーは初期化されます。それ以外の場合、メンバー自体がサブアグリゲートである場合、中括弧の省略が想定され、サブアグリゲートの最初のメンバーの初期化のために代入式が考慮されます。

8.5.1は特に集約の初期化に関するものなので、Clangが拒否するのが正しいことを意味するはずですよね?そんなに早くない。 8.5.4/3は言う:

タイプTのオブジェクトまたは参照のリスト初期化は次のように定義されます。

[…]

—それ以外の場合、Tが集計の場合、集計の初期化が実行されます(8.5.1)。

これは、中括弧の省略を含む、集計の初期化とまったく同じルールが適用されることを意味すると思います。つまり、GCCは正しく受け入れることができます。

確かに、言​​葉遣いは特に明確ではありません。では、どのコンパイラが3番目のスニペットの処理に適しているのでしょうか。ブレースの省略はリストの初期化で発生しますか、それとも発生しませんか?

47
user784668

ブレースの省略は適用されますが、C++ 11には適用されません。 C++ 14では、 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#127 のために適用されます。運が良ければ、ClangはそれをC++ 11モードにバックポートします(そうなることを願っています!)。

関連: http://en.cppreference.com/w/cpp/language/aggregate_initialization

要するに、

struct S {
    int x;
    struct Foo {
        int i;
        int j;
        int a[3];
    } b;
};
S s1 = { 1, { 2, 3, {4, 5, 6} } };
S s2 = { 1, 2, 3, 4, 5, 6}; // same, but with brace elision
S s3{1, {2, 3, {4, 5, 6} } }; // same, using direct-list-initialization syntax
S s4{1, 2, 3, 4, 5, 6}; // error in C++11: brace-elision only allowed with equals sign
                        // okay in C++14
5
kchoi