Почему поведение списка инициализаторов C++ для std::vector и std::array отличается?


код:

std::vector<int> x{1,2,3,4};
std::array<int, 4> y{{1,2,3,4}};

зачем мне нужны двойные фигурные скобки для std:: array?

2 62

2 ответа:

std::array<T, N> является агрегатом: он не имеет каких-либо объявленных пользователем конструкторов, даже не один принимая std::initializer_list. Инициализация с помощью фигурных скобок выполняется с помощью агрегатной инициализации, функция C++, которая была унаследована от C.

"старый стиль" агрегатной инициализации использует =:

std::array<int, 4> y = { { 1, 2, 3, 4 } };

С этим старым стилем агрегатной инициализации, дополнительные фигурные скобки могут быть удалены, так что это эквивалентно к:

std::array<int, 4> y = { 1, 2, 3, 4 };

однако эти дополнительные фигурные скобки могут быть удалены только " в объявлении формы T x = { a };" (в C++11 §8.5.1/11), то есть, когда старый стиль есть . Это правило, разрешающее выделение скобок, не применяется для прямой инициализации списка. Сноска здесь гласит: "фигурные скобки не могут быть исключены в других случаях использования инициализации списка."

есть сообщение о дефекте относительно этого ограничения:дефект CWG #1270. Если предлагаемая резолюция является принятый, brace elision будет разрешен для других форм инициализации списка, и следующие будут хорошо сформированы:

std::array<int, 4> y{ 1, 2, 3, 4 };

(наконечник шляпы для Ville Voutilainen для поиска отчета о дефекте.)

, потому что std::vector предлагает конструктор, который принимает в std::initializer_list<T>, в то время как std::array не имеет конструкторов и {1, 2, 3, 4} приготовился инициализации-список является в действительности не интерпретируется как std::initializer_list, но агрегатная инициализация для внутреннего массива C-стиля std::array (вот откуда берется второй набор фигурных скобок: один для std::array, один для внутреннего массива элементов C-стиля).