Скобка в инициализации 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) учитываются при инициализации агрегатного члена с помощью выражения присваивания. Если выражение присваивания может инициализировать элемент, элемент инициализируется. В противном случае, если элемент сам является субагрегатом, предполагается скобка elision и выражение присваивания рассматривается для инициализации первого члена субагрегата.

8.5.1 конкретно касается агрегатной инициализации, так что это должно означать, что Clang корректно отклонять, верно? Не так быстро. 8.5.4 / 3 говорит:

Инициализация списка объекта или ссылки типа T определяется следующим образом:

[…]

— В противном случае, если T является агрегатом, выполняется агрегатная инициализация (8.5.1).

Я думаю, что это означает, что применяются те же самые правила, что и для общей инициализации, включая удаление скобок, что означает, что GCC является правильным для принятия.

Признаюсь, формулировка не особо понятна. Итак, какой компилятор прав при обработке третьего фрагмента? Происходит ли удаление скобок при инициализации списка или нет?

44

Решение

Брейс исключение применяется, но не в C ++ 11. В C ++ 14 они будут применяться из-за http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1270 . Если вам повезет, Clang перенесет это в режим C ++ 11 (будем надеяться, что так и будет!).

20

Другие решения

Соответствующий: 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
3