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

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

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


person pmr    schedule 18.08.2011    source источник
comment
Очень похожий вопрос: почему std::initializer_list::size не constexpr (больше)? который был задан на clc++m год назад.   -  person MSalters    schedule 18.08.2011
comment
В отношении комментария MSalters 2011 года обратите внимание, что С++ 14 действительно делает std::initializer_list::size функцией constexpr, хотя С++ 11 этого не сделал. en.cppreference.com/w/cpp/utility/initializer_list/size   -  person Quuxplusone    schedule 22.01.2014


Ответы (2)


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

person Puppy    schedule 18.08.2011
comment
В том же духе: это может вызвать нетривиальное раздувание. - person MSalters; 18.08.2011

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

И то, и другое довольно неприемлемо. Не все пишут весь свой код в виде шаблонов.

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

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

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

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

Разница между std::initializer_list и списком инициализации в фигурных скобках немного похожа на разницу между int и литералом 0. Неявное преобразование объекта int в тип указателя (обычно) недопустимо, но допустимо неявное преобразование целочисленного литерала 0 в тип указателя. Принцип работы braced-init-lists такой:

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
person Nicol Bolas    schedule 18.08.2011
comment
Вы уверены в инициализации std::array из std::initializer_list? array<int, 3> x = {1,2,3} не работает на gcc 4.6, и я не могу сделать вывод, что это должно работать с n3242. - person pmr; 18.08.2011
comment
@pmr: std::array определен (в N3291) как структура и следует правилам C++0x для агрегатного типа. Следовательно, его следует инициализировать с помощью агрегатной инициализации. Таким образом, вы инициализируете его, как если бы это была структура, содержащая массив из 3 элементов. Я обновлю свой пост, чтобы объяснить это. - person Nicol Bolas; 19.08.2011
comment
@Nicol: это просто совокупная инициализация - initializer_list полностью ортогональна. - person ildjarn; 19.08.2011
comment
@ildjarn: Технически да. Но пользователям все равно, использует ли он объект std::initializer_list или агрегаты или что-то еще; все, о чем они заботятся, это то, что это работает. Что они могут использовать синтаксис {} для статической инициализации std::array. - person Nicol Bolas; 19.08.2011
comment
@Nicol: Они делают это, например, для целей. написание функции make_array, как неоднократно упоминалось в SO. В любом случае, я считаю, что утверждение Вы можете инициализировать std::array из списка инициализаторов вводит в заблуждение, когда на самом деле вы имеете в виду только то, что std::array можно инициализировать с помощью внешне похожего синтаксиса. - person ildjarn; 19.08.2011
comment
@ildjarn: Вот почему за оператором следует своего рода и не упоминается std::initializer_list тип, а просто список инициализаторов. Обратите внимание на отсутствие подчеркивания. - person Nicol Bolas; 19.08.2011