Ответ 1
речь идет о том, что нужно передавать, когда требуется удобный синтаксис.
Если вы хотите удобство размера (то есть: пользователь просто набирает список {}
без вызовов функций или слов), тогда вы должны принять все полномочия и ограничения правильного initializer_list
. Даже если вы попытаетесь преобразовать его во что-то другое, например, в какую-либо форму array_ref
, вам все равно придется иметь между ними посредник initializer_list
. Это означает, что вы не можете обойти ни одну из проблем, с которыми вы столкнулись, например, неспособность выйти из них.
Если он проходит через initializer_list
, вы должны принять эти ограничения. Поэтому альтернативой является не проходить через initializer_list
, а это означает, что вам нужно будет принять какую-либо форму контейнера со специфической семантикой. И альтернативный тип должен быть агрегатом, так что построение альтернативного объекта не будет сталкиваться с одной и той же проблемой.
Итак, вы, вероятно, пытаетесь заставить пользователя создать std::array
(или массив языков) и передать это. Ваша функция может иметь форму array_ref
, которая может быть построена из любого массива произвольного размера, поэтому функция потребления не ограничивается одним размером.
Однако вы теряете удобство размера:
foo( { "blah", 3, dog } );
против.
foo( std::array<bar, 3>{ "blah", 3, dog } );
Единственный способ избежать многословия здесь состоит в том, чтобы foo
принять std::array
в качестве параметра. Это означает, что он может принимать только массив определенного фиксированного размера. И вы не могли использовать предложенный С++ 14 dynarray
, потому что он будет использовать посредника initializer_list
.
В конечном счете, вы не должны использовать единый синтаксис инициализации для прокрутки списков значений. Это для инициализации объектов, а не для передачи списков вещей. std::initializer_list
- это класс, единственная цель которого должна использоваться для инициализации определенного объекта из произвольно длинного списка значений одинаковых типов. Он должен служить промежуточным объектом между конструкцией языка (бит-init-list) и конструктором, к которому эти значения должны быть загружены. Это позволяет компилятору знать, чтобы вызвать конкретный конструктор (конструктор initializer_list
), если ему задан соответствующий список значений с привязкой к скобкам.
Вот причина, почему класс существует.
Поэтому вы должны использовать класс исключительно для той цели, для которой он был разработан. Класс существует для того, чтобы пометить конструктор как содержащий список значений из списка с привязкой-init. Поэтому вы должны использовать его только для конструкторов, которые принимают такое значение.
Если у вас есть некоторая функция foo
, которая действует как посредник между некоторым внутренним типом (который вы не хотите показывать напрямую) и предоставленным пользователем списком значений, тогда вам нужно взять что-то еще в качестве параметра до foo
. Что-то, что имеет семантику, которую вы желаете, которую вы можете затем подавать в свой внутренний тип.
Кроме того, у вас, похоже, есть неправильное представление о initializer_list
и движении. Вы не можете выходить из initializer_list
, но вы, безусловно, можете переместиться в один:
foo( { "blah", 3, std::move(dog) } );
Третья запись во внутреннем массиве dog
будет построена по ходу.