
Привет! На связи Антон Полухин из Техплатформы Городских сервисов Яндекса. Сегодня я расскажу о ноябрьской встрече Международного комитета по стандартизации языка программирования C++, в которой принимал активное участие. Это была первая из встреч, связанных с «полировкой» C++26. Другими словами, новые фичи C++ пока не появятся — комитет должен только проработать замечания всех стран-участников, включая наши замечания от России.
Однако от плана немного отступили и втащили некоторые новинки как ответы на пожелания участников комитета:
std::integer_sequenceоброс новой функциональностью,std::formatнаучился вconstexpr.
Помимо этого, поправили множество багов, перековыряли связку Hardening + Contracts, внесли улучшения во многие части стандартной библиотеки.
std::integer_sequence
В P1789 std::integer_sequence обзавёлся методами, позволяющими использовать его в structured binding и template for:
constexpr auto [...index] = std::make_index_sequence<COUNT>();
// Теперь с `index` можно работать как с обычным pack
auto sum = (index + ...); // 0 + 1 + 2 + 3 + 4 +...
// Или даже вот так:
template for(constexpr size_t index : std::make_index_sequence<COUNT>()) {
foo<index>(std::get<index>(some_tuple));
}
Новинка будет особенно полезна для рефлексии. Она позволит писать код компактнее, без лямбд для раскрытия std::integer_sequence:
constexpr auto members = nonstatic_data_members_of(
^^Aggregate,
std::meta::access_context::unchecked()
);
constexpr auto [...indexes] = std::make_index_sequence<members.size() / 2>();
serialize_first_half(aggregate.*[:members[indexes]:]...);
std::format
Большая радость (!) для всех пользователей: std::format научился работать в constexpr. Разве что с одним ограничением: нельзя форматировать �� помощью локалей или чисел с плавающей точкой. Но даже с таким ограничением открывается большое окно возможностей: например, можно реализовать более продвинутые сообщения об ошибках в ваших библиотеках. Так, в 🐙 userver FastPimpl вместо...
// Use a template to make actual sizes visible in the compiler error message.
template <std::size_t ActualSize /* ... */>
static void Validate() noexcept {
static_assert(
Size >= ActualSize,
"invalid Size: Size >= sizeof(T) failed"
);
// ...
}
...можно будет по-человечески написать:
// Use a template to make actual sizes visible in the compiler error message.
template <std::size_t ActualSize /* ... */>
static void Validate() noexcept {
static_assert(
Size >= ActualSize,
std::format("Size should be set to at least {}.", ActualSize).c_str()
);
// ...
}
Больше деталей в P3391.
Контракты и Hardening
Контракты C++ — одна из самых ожидаемых и при этом самых холиварных фич C++26. Поэтому подгруппа Evolution целых два дня работала над различными замечаниями от стран по контрактам.
Практически все замечания были отклонены на голосованиях. Одно из ярких исключений — hardening стандартной библиотеки через контракты.
История тут приключилась, на мой взгляд, занятная: некоторые страны хотели отвязать hardening стандартной библиотеки от механизма контрактов, некоторые (например, мы) хотели сохранить возможность кастомизировать поведение при срабатывании ассерт’а в стандартной библиотеке. А вот сами разработчики стандартных библиотек C++ заметили, что hardening с контрактами... не работает.
Засада крылась в формулировках:
Hardening — это про терминирование приложения в случае нарушения контракта стандартной библиотеки.
Контракты — это про возможность обнаруживать нарушения контракта и реагировать на них.
В итоге в стандарт закралось то, чего никто не хотел. А именно: «Стандартная библиотека считается hardened, даже если нарушение контракта просто логируется». При этом неопределённое поведение при использовании стандартной библиотеки оставалось: приложение продолжало работать, но при этом делать неожиданные вещи.
Как итог, на встрече единогласно приняли P3878: «Стандартная библиотека считается hardened, если приложение терминируется при нарушении контракта». Таким образом, мы закрыли сразу пять замечаний от стран-участников.
Trivial relocation
Trivial relocation в С++26 не будет. Было решено его удалить, так как практически все разработчики компиляторов сообщили, что есть платформы и ситуации, в которых текущее поведение trivial relocation невозможно реализовать.
Trivial relocation будет дорабатываться уже для C++29, а не в C++26 P3920.
Рефлексия и friend injection
Один из вопросов от участников из России был таким: «Если теперь рефлексия С++26 позволяет делать statefull metaprogramming, то не надо ли закрыть Core issue 2118, который пытается запретить statefull metaprogramming через friend injection?»
Вопрос важен в частности для пользователей библиотеки Boost.PFR, которая как раз может использовать хитрость из бага CWG2118 для рефлексии агрегатов в C++14.
Ответ Core: «Техника, описанная в CWG2118, позволяет намного больше, чем C++26 reflection. В частности, C++26 reflection injection не может вырваться за пределы класса или функции. При этом CWG2118 слишком строг в текущей формулировке, но закрывать как Not a Defect мы его не готовы».
Хорошо, что Boost.PFR работает и без использования хаков из CWG2118.
Прочие фиксы
optional<T&>теперь обязан быть trivially copyable P3836;добавлены
std::moveиnoexceptдля различныхflat_*контейнеров P3567;std::execution::when_allтеперь отправляет стоп-сигналы, только если один из «детей» их отправляет P388;atomic_ref<T>научился конвертироваться вatomic_ref<const T>P3860.
И ещё почти сотня менее заметных багфиксов, доработок и улучшений.
Вместо итогов
Работа комитета не останавливается, подгруппы разбирают баги в онлайне. Сделать предстоит много: всего к C++26 было отправлено более 400 замечаний.
Остаётся нерешённым множество важных для нас комментариев, которые влияют на производительность и надёжность программ на C++. В частности, на этом заседании не дошли руки до P3725, который делает надёжный и безопасный std::ranges::filter, не подверженный проездам по памяти и Segmentation Fault в примерах наподобие:
std::vector<std::string> coll1{"Amsterdam", "Berlin", "Cologne", "LA"};
// Перемещаем длинные строки в обратном порядке в другой контейнер
auto large = [](const auto& s) { return s.size() > 5; };
auto sub = coll1 | std::views::filter(large)
| std::views::reverse
| std::views::as_rvalue
| std::ranges::to<std::vector>();
А в скором времени пройдут конференции по C++, где можно будет поймать представителей РГ21, задать им вопросы, узнать что-то новое и интересное.
22 ноября → YADRO System Level Meetup;
15 декабря → Встреча РГ21.
Буду рад встрече!
P.S.: некоторые ссылки на P???? документы могут ещё не работать, т.к. они не опубликованы. Со временем ссылки заработают
