Почему не std:: initializer_list - встроенный язык?

Почему нет std::initializer_list встроенного ядра?

Мне кажется, что это довольно важная особенность С++ 11, но у нее нет собственного зарезервированного ключевого слова (или чего-то подобного).

Вместо этого initializer_list это просто класс шаблона из стандартной библиотеки, который имеет специальное неявное сопоставление из нового синтаксиса braced-init-list {...}, который обрабатывается компилятором.

Поначалу это решение довольно хаки.

Является ли это тем, как теперь будут реализованы новые дополнения к языку С++: неявные роли для некоторых классов шаблонов, а не языком core?


Пожалуйста, рассмотрите следующие примеры:

   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, теперь variadic templates), почему бы не повторить использование синтаксиса (и заставить его чувствовать себя встроенным).
  • только существующий контейнер, можно добавить const и &

Все они уже являются частью языка. Я только написал свои 3 первые идеи, я уверен, что есть many другие подходы.

Ответ 1

Уже были примеры "основных" языковых функций, возвращающих типы, определенные в пространстве имен std. typeid возвращает std::type_info и (возможно, растягивая точку) sizeof возвращает std::size_t.

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

Теперь, для списков инициализаторов, для генерации объекта не требуется ключевое слово, синтаксис - это зависящие от контекста фигурные скобки. Кроме того, это то же самое, что и type_info. Лично я не думаю, что отсутствие ключевого слова делает его "более взломанным". Чуть более удивительно, возможно, но помните, что цель заключалась в том, чтобы тот же синтаксис синтаксического кодирования, который уже был разрешен для агрегатов.

Итак, вы, вероятно, можете ожидать большего от этого принципа дизайна в будущем:

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

Следовательно:

  • Если новая функция требует сложного типа и может быть введена без новых ключевых слов, тогда вы получите то, что у вас здесь, синтаксис "основного языка" без новых ключевых слов и использует типы библиотек от std.

По-моему, я думаю, что нет абсолютного разделения на С++ между "основным языком" и стандартными библиотеками. Они разные главы в стандарте, но каждый ссылается на другой, и он всегда был таким.

В С++ 11 существует другой подход, который заключается в том, что lambdas представляет объекты, которые имеют анонимные типы, сгенерированные компилятором. Поскольку у них нет имен, они вообще не находятся в пространстве имен, но не в std. Однако это не подходит для списков инициализаторов, потому что вы используете имя типа при написании конструктора, который принимает его.

Ответ 2

Комитет по стандартизации С++, похоже, предпочитает не добавлять новые ключевые слова, возможно, потому, что это увеличивает риск нарушения существующего кода (устаревший код может использовать это ключевое слово как имя переменной, класс или что-то еще).

Кроме того, мне кажется, что определение std::initializer_list в качестве шаблонного контейнера - довольно элегантный выбор: если бы это было ключевое слово, как бы вы получили доступ к его базовому типу? Как бы вы пробовали его? Вам понадобится множество новых операторов, и это просто заставило бы вас вспомнить больше имен и больше ключевых слов, чтобы делать то же самое, что вы можете делать со стандартными контейнерами.

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

UPDATE:

Тогда зачем вводить новый тип, вместо того, чтобы использовать некоторую комбинацию существующих? (из комментариев)

Во-первых, все остальные контейнеры имеют методы для добавления, удаления и размещения элементов, которые нежелательны для коллекции, сгенерированной компилятором. Единственным исключением является std::array<>, который обертывает массив C-стиля фиксированного размера и поэтому остается единственным разумным кандидатом.

Однако, поскольку Nicol Bolas правильно указывает в комментариях, другое фундаментальное различие между std::initializer_list и всеми другими стандартными контейнерами ( включая std::array<>), состоит в том, что последние имеют семантику значений, а std::initializer_list имеет ссылочную семантику. Например, копирование std::initializer_list не приведет к копированию содержащихся в нем элементов.

Более того (еще раз, любезно предоставлено Nicol Bolas), имея специальный контейнер для списков инициализации скобок, позволяет перегружать то, как пользователь выполняет инициализацию.

Ответ 3

Это ничего нового. Например, for (i : some_container) полагается на существование определенных методов или автономных функций в классе some_container. С# даже больше полагается на свои библиотеки .NET. На самом деле, я думаю, это довольно элегантное решение, потому что вы можете сделать ваши классы совместимыми с некоторыми языковыми структурами, не усложняя спецификации языка.

Ответ 4

Это действительно ничего нового и сколько указали, эта практика была там на С++ и есть, скажем, на С#.

Андрей Александреску упомянул об этом неплохо: вы можете подумать об этом как о части мнимого "основного" пространства имен, тогда это будет иметь больше смысла.

Итак, это действительно что-то вроде: core::initializer_list, core::size_t, core::begin(), core::end() и т.д. Это просто неудачное совпадение, что пространство имен std содержит внутри него некоторые конструкторы основного языка.

Ответ 5

Он не только полностью работает в стандартной библиотеке. Включение в стандартную библиотеку не означает, что компилятор не может играть умные трюки.

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

Другими словами, int i {5}; может быть эквивалентно int i(5); или int i=5; или даже intwrapper iw {5}; Где intwrapper - это простой класс-оболочка над int с тривиальным конструктором, принимающим initializer_list

Ответ 6

Он не является частью основного языка, потому что он может быть полностью реализован в библиотеке, только строка operator new и operator delete. Какое преимущество было бы в том, чтобы компиляторы усложнили сборку?