Почему размер не является аргументом шаблона std:: initializer_list?

std::initializer_list создается компилятором из списка инициализации, заключенного в скобки, и размер этого списка должен быть постоянной времени компиляции.

Итак, почему комитет решил опустить размер из аргументов шаблона? Это, возможно, предотвращает некоторые оптимизации и делает некоторые вещи невозможными (инициализация std::array от std::initializer_list).

Ответ 1

Один из достоинств существующей системы заключается в том, что вы можете экспортировать функции, которые принимают initializer_list из DLL. Если бы они были заархивированы по размеру, они должны были быть отправлены в качестве источника.

Ответ 2

Если initializer_list было определено как std::initializer_list<type, size>, то любая функция, которая принимает initializer_list<type>, где type - это конкретный тип, теперь должна быть функцией шаблона, основанной на этом размере списка. Или они должны будут потребовать, чтобы пользователи передали initializer_list определенного типа и размера.

Оба они довольно неприемлемы. Не все записывают весь свой код в качестве шаблонов.

Вы можете инициализировать std::array из скопированного-init-списка ({} с материалом в середине). Но это не то же самое, что std::intiializer_list. Класс array является агрегированным типом. Это структура, которая содержит один элемент, который является открытым массивом. Следовательно, на соответствующих реализациях С++ 11 это должно скомпилировать:

std::array<int, 3> myArray = {1, 3, 5};

Однако {1, 3, 5} не является объектом std::initializer_list; это просто бит-init-list, который можно использовать для инициализации соответствующих типов.

Вы не можете передать объект std::initializer_list конструктору aggegate (поскольку агрегаты не имеют конструкторов), но вы можете использовать список braced-init для вызова инициализации агрегата для инициализации std::array, как и вы для любой структуры, содержащей массив.

Разница между std::initializer_list и braced-init-list немного похожа на разницу между int и литералом 0. Это не (обычно) законно неявно преобразовывать объект int в тип указателя, но законно неявно преобразовывать целочисленный литерал 0 в тип указателя. Способ работы с бит-init-списками выглядит следующим образом:

int i = 0;    //Legal
void *j = 0;  //Legal
void *k = i;  //Not legal

std::array<int, 3> myArray = {1, 3, 5};             //Legal
std::initializer_list<int> myInitList = {1, 3, 5};  //Legal
std::array<int, 3> myArray = myInitList;            //Not legal