Почему не std::initializer_list
встроен базовый язык?
Мне кажется, что это довольно важная особенность C ++ 11, но у него нет собственного зарезервированного ключевого слова (или чего-то подобного).
Вместо этого initializer_list
это просто класс шаблона из стандартной библиотеки, который имеет специальное неявное сопоставление из нового списка инициализации в фигурных скобках. {...}
синтаксиса скобках, который обрабатывается компилятором.
На первый взгляд это решение довольно хакерское .
Так будут ли теперь реализовываться новые дополнения к языку C ++: неявными ролями некоторых классов шаблонов, а не базовым языком?
Пожалуйста, рассмотрите эти примеры:
widget<int> w = {1,2,3}; //this is how we want to use a class
почему был выбран новый класс:
widget( std::initializer_list<T> init )
вместо использования чего-то похожего на любую из этих идей:
widget( T[] init, int length ) // (1)
widget( T... init ) // (2)
widget( std::vector<T> init ) // (3)
- классический массив, вы, вероятно, могли бы добавить
const
здесь и там - три точки уже существуют в языке (var-args, теперь вариативные шаблоны), почему бы не использовать синтаксис повторно (и сделать его встроенным )
- только существующий контейнер, можно добавить
const
и&
Все они уже являются частью языка. Я написал всего 3 свои первые идеи, уверен, что есть много других подходов.
источник
std::array<T>
не более чем «часть языка»std::initializer_list<T>
. И это далеко не единственные библиотечные компоненты, на которых основан язык. Смnew
/delete
,type_info
различные типы исключений,size_t
и т.д.const T(*)[N]
, потому что это очень похоже на то, какstd::initializer_list
работает.std::array
массив статического размера является менее желательной альтернативой.Ответы:
Уже были примеры «основных» языковых функций, которые возвращали типы, определенные в
std
пространстве имен.typeid
возвращаетсяstd::type_info
и (возможно, растягивая точку)sizeof
возвращаетсяstd::size_t
.В первом случае вам уже нужно включить стандартный заголовок, чтобы использовать эту функцию так называемого «основного языка».
Теперь для списков инициализаторов случается, что для создания объекта не требуется ключевое слово, синтаксис - контекстно-зависимые фигурные скобки. В остальном это то же самое, что и
type_info
. Лично я не думаю, что отсутствие ключевого слова делает его «более хакерским». Возможно, это немного более удивительно, но помните, что цель заключалась в том, чтобы разрешить тот же синтаксис в фигурных скобках, который уже был разрешен для агрегатов.Так что да, вы, вероятно, можете ожидать большего от этого принципа дизайна в будущем:
std
внутрь, а не как встроенные.Отсюда:
std
.Я думаю, что все сводится к тому, что в C ++ нет абсолютного разделения на «основной язык» и стандартные библиотеки. Это разные главы стандарта, но каждая из них ссылается на другую, и так было всегда.
В C ++ 11 есть еще один подход, заключающийся в том, что лямбда-выражения вводят объекты, которые имеют анонимные типы, сгенерированные компилятором. Поскольку у них нет имен, они вообще не находятся в пространстве имен, тем более не в
std
. Однако это не подходит для списков инициализаторов, потому что вы используете имя типа, когда пишете конструктор, который его принимает.источник
type_info
иsize_t
хорошие аргументы ... ну,size_t
это просто определение типа ... так что давайте пропустим это. Разница междуtype_info
иinitializer_list
заключается в том, что первый является результатом явного оператора, а второй - неявного действия компилятора. Мне также кажется, что этоinitializer_list
можно было бы заменить некоторыми уже существующими контейнерами ... или еще лучше: любой, который пользователь объявляет как тип аргумента!vector
который принимает,array
тогда вы можете построить вектор из любого массива правильного типа, а не только из одного, созданного синтаксисом списка инициализаторов. Я не уверен, что было бы плохо конструировать контейнеры из любогоarray
, но это не намерение комитета вводить новый синтаксис.std::array
даже конструкторов нет.std::array
Дело просто агрегатно-инициализации. Кроме того, я приветствую вас присоединиться ко мне в чате Lounge <C ++>, так как это обсуждение становится слишком длинным.Комитет по стандартизации C ++, похоже, предпочитает не добавлять новые ключевые слова, вероятно, потому, что это увеличивает риск нарушения существующего кода (устаревший код может использовать это ключевое слово как имя переменной, класса или чего-то еще).
Более того, мне кажется, что определение
std::initializer_list
как шаблонный контейнер - довольно элегантный выбор: если бы это было ключевое слово, как бы вы получили доступ к его базовому типу? Как бы вы его повторили? Вам также понадобится множество новых операторов, и это просто заставит вас запомнить больше имен и больше ключевых слов, чтобы делать то же самое, что вы можете делать со стандартными контейнерами.Лечение
std::initializer_list
контейнера как любого другого дает вам возможность написать общий код, который работает с любым из этих элементов.ОБНОВИТЬ:
Начнем с того, что все остальные контейнеры имеют методы для добавления, удаления и размещения элементов, что нежелательно для коллекции, созданной компилятором. Единственное исключение -
std::array<>
это массив фиксированного размера в стиле C, который, следовательно, останется единственным разумным кандидатом.Однако, как Никол Болас правильно указует в комментариях, другой, принципиальное отличие
std::initializer_list
и все другие стандартные контейнеры ( в том числеstd::array<>
) в том , что последние из них имеет семантику значений , в то время какstd::initializer_list
имеет эталонную семантику . Копированиеstd::initializer_list
, например, не будет вызывать копию элементов , которые он содержит.Более того (опять же, любезно предоставлено Николаем Боласом) наличие специального контейнера для списков инициализации фигурных скобок позволяет перегружать способ, которым пользователь выполняет инициализацию.
источник
std::array
. Ноstd::array
выделяет память приstd::initializaer_list
обертывании массива времени компиляции. Думайте об этом как о разнице междуchar s[] = "array";
иchar *s = "initializer_list";
.std::array
не выделяет никакой памяти, это обычнаяT arr[N];
, та же самая вещь, которая поддерживаетstd::initializer_list
.T arr[N]
выделяет память, возможно, не в динамической куче, а где-то еще ... То же самоеstd::array
. Однако непустой объект неinitializer_list
может быть создан пользователем, поэтому он, очевидно, не может выделить память.В этом нет ничего нового. Например,
for (i : some_container)
полагается на наличие определенных методов или автономных функций вsome_container
классе. C # даже больше полагается на свои библиотеки .NET. На самом деле, я думаю, что это довольно элегантное решение, потому что вы можете сделать свои классы совместимыми с некоторыми языковыми структурами, не усложняя спецификацию языка.источник
begin
иend
методы. Это немного другое ИМО.iterable class MyClass { };
initializer_list
хотяВ этом действительно нет ничего нового, и, как многие отмечали, такая практика была и в C ++, и, например, в C #.
Андрей Александреску упомянул об этом хороший момент: вы можете думать об этом как о части воображаемого «основного» пространства имен, тогда это будет иметь больше смысла.
Таким образом, это на самом деле что - то вроде:
core::initializer_list
,core::size_t
,core::begin()
,core::end()
и так далее. Это просто досадное совпадение, чтоstd
пространство имен имеет внутри некоторые конструкции ядра.источник
Он не только может полностью работать в стандартной библиотеке. Включение в стандартную библиотеку не означает, что компилятор не умеет хитрить.
Хотя это может быть не во всех случаях, он может очень хорошо сказать: этот тип хорошо известен или простой тип, давайте проигнорируем
initializer_list
и просто иметь в памяти образ того, каким должно быть инициализированное значение.Другими словами ,
int i {5};
может быть эквивалентноint i(5);
илиint i=5;
дажеintwrapper iw {5};
гдеintwrapper
простой оберткой класса над междунар с тривиальным конструктор принимаетinitializer_list
источник
int i {5}
включает в себя что- либоstd::initializer_list
, неверна.int
не имеет конструктораstd::initializer_list
, поэтому5
используется непосредственно для его создания. Так что основной пример неуместен; оптимизации просто не нужно делать. Кроме того, посколькуstd::initializer_list
компилятор создает и проксирует `` воображаемый '' массив, я думаю, он может способствовать оптимизации, но это `` волшебная '' часть компилятора, поэтому она не зависит от того, может ли оптимизатор в целом сделать что-нибудь умное с красивым тупой объект, содержащий 2 итератора, результатОн не является частью основного языка, потому что он может быть полностью реализован в библиотеке, только в строке
operator new
иoperator delete
. Какое преимущество было бы в том, чтобы сделать компиляторы более сложными для встраивания?источник