Почему std:: initializer не является встроенным языком?


почему бы и нет std::initializer_list встроенный основной язык?

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

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

сначала думал, это решение вполне hacky.

так ли теперь будут реализованы новые дополнения к языку C++: by неявных функций некоторых классов шаблонов, а не по базовый язык?


пожалуйста, рассмотрите эти примеры:

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

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

6 91

6 ответов:

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

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

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

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

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

отсюда:

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

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

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

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

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

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

обновление:

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

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

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

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

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

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

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

так, это на самом деле что-то вроде: 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 это простой класс-оболочка над int с тривиальным конструктором, принимающим initializer_list

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