Шрифт
На шаг ближе к С++20. Итоги встречи в Торонто
Play

На шаг ближе к С++20. Итоги встречи в Торонто

Несколько недель назад состоялась встреча международного комитета по стандартизации C++. На ней люди (в основном) не разменивались на мелочи и совершили несколько больших шагов на пути к С++20.

  • Расширению Concepts быть в C++20!
  • Ranges, Networking и Coroutines/сопрограммы: выпущены в эксперимент в виде TS.
  • Модули: черновик TS готов.
Concepts

Замечательная вещь под названием Concepts внесена в черновик будущего стандарта С++20. Это большая радость для разработчиков обобщенных библиотек, использующих идиому SFINAE.

В вашей библиотеке есть функции `*_fast` и `*_slow`, принимающие на вход два шаблонных параметра `v` и `data`:

    `*_fast` — сильно соптимизированы, но требуют, чтобы следующие операции возвращали T& и были валидны:

Без концептов эта задача, например, решается через `std::enable_if_t` и множество нечитаемого шаблонного кода.

С концептами всё намного проще:

  • писать более простой шаблонный код,
  • выдавать более короткие сообщения об ошибках при использовании неверных шаблонных параметров (в теории, пока что это не так!).
Ranges TS

Ranges увидят свет в виде технической спецификации. Это значит, что поэкспериментировать с ними можно будет еще до C++20.

С Ranges можно писать `sort(container)` вместо `sort(container.begin(), container.end())`, нужно только заиспользовать нужный namespace.

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

Нечто подобное Александреску делал для получения супербыстрого поиска.

Любителям SFINAE и обобщённых библиотек Ranges тоже принесут счастье, так как они определяют огромное количество концептов: Sortable, Movable, Copyable, DefaultConstructible, Same…

Можно поэкспериментировать, скачав библиотеку отсюда. Вот последний доступный черновик Ranges.

Networking TS

Все, что необходимо для работы с сокетами (в том числе для асинхронной работы), будет выпущено в эксперимент еще до C++20. В основе Networking TS лежит доработанный и улучшенный ASIO.

Вот пара приятных различий:

  • В Networking TS можно передавать move-only callback. В ASIO для этого надо было на свой страх и риск поплясать с бубном макросом BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS. Так что если у вас есть функциональный объект с unique_ptr, то его можно спокойно использовать для callback.
  • Больше constexpr для базовых типов (например, для ip::address).
  • Вменяемые способы передачи аллокаторов: можно в класс-callback добавить allocator_type и метод allocator_type get_allocator(); можно специализировать шаблон associated_allocator и описать, какие методы класса надо дергать вместо get_allocator().
Coroutines TS

Самый смак получается, если смешать Coroutines TS и Networking TS. Тогда вместо асинхронного нечитабельного кода на +100 строк можно получить то же самое, но на 40 строк:

Но вот плохие новости: такую интеграцию Coroutines TS и Networking TS в стандарт еще не привнесли. Пока что придется реализовывать ее самим.

С сопрограммами уже можно поэкспериментировать в CLANG-6.0, если использовать флаги -stdlib=libc++ -fcoroutines-ts, например, тут. Вот последний доступный черновик Coroutines.

Модули

Подготовлен черновик TS. Дело сдвинулось и есть шансы увидеть модули уже в течение года!

Когда вы собираете проект, каждый файл cpp может компилироваться параллельно (это хорошо, отличная масштабируемость).

Однако, как правило, вы используете одни и те же заголовочные фалы в каждом файле cpp. За счет того, что компиляция различных файлов cpp никак не связана друг с другом, при каждой компиляции компилятор разбирает одни и те же заголовочные файлы снова и снова. Именно этот разбор и тормозит (заголовочный файл iostream весит более мегабайта, подключите 20 подобных заголовочных файлов — и компилятору придётся просмотреть и разобрать около 30 мегабайт кода при компиляции одного файла cpp).

И тут на сцену выходят модули! Модуль — это набор файлов, собранных воедино и сохранённых на диск в понятном для компилятора бинарном виде. Таким образом, при подключении модуля компилятор просто считает его с диска в свои внутренние структуры данных (минуя этапы открытия нескольких фалов, парсинга, препроцессинга и некоторых другие вспомогательные этапы).

Дополнительный прирост скорости при компиляции будет получен за счёт того, что в модуле вы явно указываете его публичный интерфейс. То есть компилятор сможет сделать ряд оптимизаций ещё при создании модуля. Это сильно уменьшит затраты оперативной памяти, ускорит поиск подходящих перегруженных функций, структур и т. д. за счёт того, что их попросту будет меньше.

И наконец, финальная стадия сборки проекта — линковка. В данный момент линковщик может тратить много времени на выкидывание одинаковых блоков скомпилированного кода (вы написали функцию inline/force_inline, 100 раз её использовали, а компилятор решил её не встраивать — линкер выкинет 99 скомпилированных тел вашей функции и оставит одно). С модулями такого происходить не должно, поскольку файл модуля не будет «вкомпиливаться» внутрь собранного файла cpp.

Модули в черновике не экспортируют макросы, поэтому будет сложновато использовать их для системных файлов с множеством макросов (`<windows.h>`, я на тебя намекаю!) и поддерживать код, использующий модуль и его старый заголовочный файл (если у вас std::string описан в модуле и в заголовочном файле , то при подключении модуля и заголовочного файла будет multiple definitions, поскольку макрос для include guards не экспортируется из модуля). Это как раз такие модули, за которые вы проголосовали в прошлом посте (ваши голоса мы донесли до комитета).

Мелочи, принятые в C++20

В C++20 можно будет инициализировать bitfields в описании класса:

Можно будет понимать платформы endianness стандартными методами:

Можно будет инициализировать поля структур, прям как в чистом C:

У лямбд можно будет явно указывать шаблонные параметры:

Заслуги РГ21

На встречу в Торонто мы ездили с несколькими предложениями:

    — конкурентные ассоциативные контейнеры. Комитет хорошо встретил предложение, посоветовал провести эксперименты для улучшения ряда мест, посоветовал улучшения в интерфейсе. Начали работу над следующей версией предложения. — integers, размер (количество байт) которых задаётся на этапе компиляции. Возникли споры по поводу интерфейса (указывать шаблонным параметром биты, байты или машинные слова), так что в следующей итерации необходимо будет привести плюсы и минусы различных подходов. — наше предложение направить усилия в сторону разработки `constexpr_allocator` вместо `constexpr_string + constexpr_vector`. Встретили крайне благосклонно, проголосовали за. Следующие наши шаги — прорабатывать тему вместе с Давидом. — constexpr для std::complex. Предложение было одобрено и теперь находится в подгруппе LWG (вместе с предложением на constexpr для стандартных алгоритмов). Должно быть в скором времени смержено в черновик C++20.

В комитете С++ активно работают над идеями рефлексии и метаклассов. Обе эти идеи требуют хорошей поддержки constexpr-вычислений от стандартной библиотеки, так что предложения на добавление constexpr — это в основном задел на будущее, чтобы при принятии в стандарт рефлексии можно было использовать стандартные классы и функции.

Кроме того, ряду библиотек уже нужны constexpr-функции: [1], [2].

    — starts_with и ends_with для строк. Комитет предложил сделать это в виде свободных функций. Один из присутствующих сказал, что у них в компании есть эти методы и их используют чаще, чем остальные алгоритмы вместе взятые. Все с нетерпение ждут новой версии proposal. — функция contains(key) member для классов [unordered_]map/set/multimap/multiset. Комитету идия пришлась по душе, почти отправили в LWG для внедрения в C++20.
На подходе

Обсуждали предложение по форматированию текста, и многим понравились предлагаемые возможности (вероятно, потому, что людям нравится Python):

Обсуждали ring_span, который по функциональности напоминает boost::circular_buffer, но не владеет элементами (является view над контейнером).

На подходе битовые операции. Когда их примут, правильным ответом на вопрос «Как подсчитать количество выставленых битов в переменной X?» на собеседованиях станет «std::popcount(X)».

Планы и прочее

РГ21 планирует в ближайшее время написать предложения на std::stacktrace (в качестве прототипа послужит Boost.Stacktrace), доработать предложение на std::shared_library и на экспорт символов из динамических библиотек.

Если у вас есть идеи для C++20, если вы нашли проблемы в C++17/14/11 либо просто хотите подстегнуть разработку той или иной фичи C++ — заходите на сайт рабочей группы stdcpp.ru. Добро пожаловать!

Есть желание помочь с написанием предложений и внести своё имя в историю? Мы подготовили мини-инструкцию по написанию предложений.

📎📎📎📎📎📎📎📎📎📎