Почему поведение 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).

Другие вопросы по тегам