На днях прошла встреча международного комитета по стандартизации C++ в американском городе Кона. Это была не просто встреча, а feature freeze! Никакие серьёзные новые идеи больше не могут просачиваться в стандарт, остаётся лишь пара встреч на добавление предварительно одобренных вещей, исправление недочётов и устранение шероховатостей.
Ожидать ли Модули и Корутины в C++20, будет ли там быстрая библиотека для форматирования вывода, сможет ли она работать с календарями, добавили ли std::stacktrace, начнёт ли компилятор сам вызывать std::move в ряде случаев, приняли ли std::flat_map? Всё это и многое другое ожидает вас под катом.
Coroutines TS
Самые жаркие дебаты разгорелись вокруг сопрограмм. Комитету предстояло рассмотреть три различных подхода к сопрограммам и решить, принимать в стандарт имеющиеся Coroutines TS, либо идти другим путём.
Выбор был не простой, у каждого подхода есть свои минусы и плюсы:
- N4775:
- + нет ограничений на то, что сопрограммы должны быть описаны в заголовочном файле
- − нет строгих гарантий, что не произойдёт динамическая аллокация
- ± не самый простой интерфейс (P1477R0 это исправляет)
- − страшненькие ключевые слова co_await и co_yield (предложение P1485R0 от РГ21 это исправляет)
- + 3 года применяются на практике
- P1063R2:
- + нет динамических аллокаций
- − сопрограммы должны быть описаны в заголовочном файле или самим надо хитровыкручиваться с type erasure
- − ещё более страшные ключевые operator[<-] и [->]
- − нет рабочего прототипа
- − не самый простой интерфейс для создания асинхронных вещей
- P1430R0:
- + нет динамических аллокаций
- − сопрограммы должны быть описаны в заголовочном файле или самим надо хитро выкручиваться с type erasure
- + нет страшных ключевых слов, всё гладенько
- + пользователи корутин не видят страшных корутиновых внутренностей (даже не видят co_await аналогов, всё из коробки работает)
- − первое предложение, ни разу не обсуждалось, требует кучи доработок
- − невозможно реализовать на текущих технологиях (требуют поддержки структур динамического размера), требуют огромных трудозатрат для реализации
- ± немного напоминают лапшу из callback
После долгих дебатов сопрограммы были приняты в C++20 в том виде, в котором они были в Coroutines TS (с co_* префиксами и старыми точками кастомизации).
Modules
На обсуждение модулей повлиял один интересный документ с замерами производительности:
P1441R0. Трактовать результаты можно по разному: от «существующие системы сборки и реализация модулей ещё недостаточно оптимизированы» до «модули плохо масштабируются с ростом сложности проекта».
Помимо этого документа, комитет обсудил ряд небольших правок к текущим модулям. В итоге, спустя 15 лет обсуждения, прототипирования и экспериментов с внедрениями, модули были приняты в C++20.
Format
Good news everyone! Если не найдут фатальных недостатков в подгруппе Library, то в C++20 можно будет безопасно и очень быстро форматировать строки. Скажите «до свидания» std::ios, std::locale и прочим ужасам 90-х! Теперь Python подобный синтаксис для форматирования доступен из коробки в С++: P0645R5.
Более того, было принято предложение на интеграцию нового форматирования и календарных времён P1361R0. Если всё пойдёт по плану, то и даты можно будет выводить по-человечески!
Networking, Executors и Properties
Executors являются важным кирпичиком для поддержки Networking в C++ из коробки. Для Executors нужны Properties — возможность модифицировать тип данных, в зависимости от параметра переданного на этапе компиляции, не меняя концепт типа.
Properties описаны в P1393R0. Не смотря на то, что текста для включения в стандарт всего пара страничек, предложение вызвало бурные обсуждения. Предложение позволяет делать практически всесильные точки кастомизации, менять поведение любых функций, использующих Properties.
В итоге решено было Properties включать в язык только в C++23, а соответственно и Executors, и Networking в C++20 не появятся.
Прочее
В черновик C++20 уже были внесены следующие изменения:
- Структуры без конструкторов (агрегаты) теперь можно инициализировать, используя круглые скобки P0960. На практике это значит, что теперь std::make_shared, std::make_unique, std::*::emplace* будут корректно работать с агрегатами без ошибок компиляции
- Были добавлены функции lerp для линейной интерполяции P0811
- Добавлена возможность векторизировать алгоритмы стандартной библиотеки P1001
- Методы std::span теперь возвращают беззнаковые типы (по аналогии со всей стандартной библиотекой) + была добавлена функция std::ssize для получения размера контейнера в виде знакогового числа P1227
- Unordered контейнеры научились искать значения, используя заранее посчитанный хеш P0920
Много других вещей ожидают финального ревью в подгруппах Library и Core, для включения в C++20:
- Эффективное ожидание на std::atomic; классы семафоров и барьеров P1135
- std::flat_map P0429
- std::flat_set P1222
- std::function_ref P0792
- constexpr для <cmath> и <cstdlib> P0533
- std::ranges::to<любой-контейнер> для сохранения диапазона значений в контейнер P0533
- Возможность эффективно извлекать строки из std::*stringstream и передавать во владение пользовательские строки P0408
- Множественные правки для operator<=>, ranges, constexpr
Заслуги РГ21
В самый первый день за горячо любимое в Яндекс.Такси предложение на Stacktrace P0881R3 взялась подгруппа Core. Замечания по дизайну были дополнительно обсуждены в подгруппе LEWG, ещё раз проработаны в Core. В итоге в течении всей недели вносились правки и велись обсуждения. В черновик стандарта предложение ещё не включено, но должно оказаться в C++20 (если не найдут вдруг какой-то фатальный недостаток).
До обсуждения нашей идеи P1485R0 на приведение ключевых слов для корутин дело не дошло.
Также в SG1 Concurrency обсуждали идею concurrent unordered map P1485R0. Нас попросили перепроверить, что предложенное API позволяет избежать reader contention. Также сказали поисследовать concurrent unordered контейнеры, которые не имеют функции erase и не защищают значение контейнера от конкурентной модификации.
Предложение от ZaMaZaN4iK на специализацию std::hash для различных классов стандартной библиотеки P1406R0 решено было сильно порезать. Комитет порекомендовал оставить специализации только для std::pair, std::tuple, std::array и std::basic_string от пользовательских аллокаторов.
В подгруппе цифр SG6 обсудили механизм для взаимодействия различных новых классов чисел P0880R2. Предложение позволяет специализировать два шаблона, получить полный набор математических операций и сравнений для всех новых типов. По итогам обсуждения решили попробовать расширить механизм, чтобы им можно было пользоваться не только для нужд стандартной библиотеки, но и пользователи могли использовать эти операторы для своих типов.
Также обсуждали наши незначительные предложения, включая feature testing macro P1424R0 и политики на их добавление в стандарт.
Быстро обсудили нашу идею, позволяющую компилятору убирать лишние копирования R0889R1. Нам сказали продолжать работу в этом направлении и накидали примеров, которые не должны ломаться с новыми правилами.
Вместо итогов
C++20 будет так же разительно отличаться от C++17, как С++11 отличался от C++03. Огромное количество новых технологий и новых парадигм: Concepts, Contracts, Ranges, Modules, Coroutines, constexpr контейнеры и constexpr динамический полиморфизм, «ниблойды» и т. д.
В скором времени мы, Рабочая Группа 21, отправим комментарии к черновику стандарта C++20. Поэтому, если у вас есть какая-то боль или вы не согласны с каким-то нововведением, пожалуйста, оставляйте свои мысли на этой странице.
Следующее собрание международного комитета будет летом, на нём могут начать рассматривать нововведения для C++23. Если вы хотите что-то изменить в C++ или предложить свою идею, то всегда можете написать на https://stdcpp.ru/, где люди из РГ21 помогут вам донести ваши желания до комитета.
Желаете поговорить с нами вживую? Скоро состоится открытая встреча РГ21, следите за анонсами на events.yandex.ru. Так же ищите нас на апрельской конференции C++ Russia в Москве.
Автор: Antony Polukhin