Почему поведение C++ initializer_list для std::vector и std::array отличается?
Код:
std::vector<int> x{1,2,3,4};
std::array<int, 4> y{{1,2,3,4}};
Зачем мне нужны двойные фигурные скобки для std::array?
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. Если предложенное решение будет принято, исключение скобок будет разрешено для других форм инициализации списка, и будет правильно сформировано следующее:
std::array<int, 4> y{ 1, 2, 3, 4 };
(Шляпная подсказка Вилле Воутиленену за поиск сообщения о дефекте.)
Так как std::vector
предлагает конструктор, который принимает std::initializer_list<T>
, в то время как std::array
не имеет конструкторов и тому {1, 2, 3, 4}
фигурный список инициализации фактически не интерпретируется как std::initializer_list
, но агрегатная инициализация для внутреннего массива в стиле C std::array
(вот откуда берется второй набор скобок: один для std::array
один для внутреннего массива элементов в стиле C).