Вчера прошла встреча рабочей группы ISO C++, добавляли фичи в C++23, исправляли C++20. Мы участвуем в работе комитета, поэтому сегодня поделюсь с вами свежими новостями о развитии стандарта.
Должен заметить, что международный комитет в онлайне работает совсем уж неторопливо… Настолько неторопливо, что на февральской встрече из полезного приняли только std::to_underlying() — функцию, преобразовывающую значение enum к нижележащему целочисленному типу:
enum class ABCD : std::uint64_t { A = 0x1012, B = 0x405324, };
constexpr std::uint64_t value = std::to_underlying(ABCD::A);
std::vector<std::byte> data;
data.reserve(200);
Тогда аллокатор выделит память не под 200 байт, а под 224. Однако у std::vector до C++23 нет никакой возможности об этом узнать и использовать оставшиеся 24 байта (какое расточительство!). Из-за этого могли происходить лишние реаллокации. Например, если вы вставляли в вектор более 200, но менее 225 байт, то вектор мог реаллоцироваться на 400 байт (при этом аллокатор отдал бы нам памяти под 448 байт).
В C++23 добавили новый интерфейс, и теперь аллокаторы могут сообщать вам, под какое количество элементов была выделена память на самом деле. std::vector сможет использовать это из коробки. Ни одного байтика не пропадёт!
Полное описание предложения доступно в документе P0401R6.
std::ispanstream isp{"10 20 30"};
int i;
isp >> i;
std::spanstream может работать с любыми символами, расположенными последовательно в памяти (другими словами, со всем, от чего можно сконструировать std::span).
Подробности и больше примеров можно найти в документе P0448R4.
Однако пользователей такого класса в C++23 ожидается не так много, потому что std::format_to был принят ещё в C++20 и обладает несколько большей производительностью. Кстати, о нём…
auto s = std::format("{:d}", "I am not a number");
Скорее всего, разработчик допустил ошибку при написании этого кода и указал строку формата. При выполнении с текущим стандартом C++20 кинет исключение std::format_error.
Но можно сделать лучше — проверять описание формата и типы аргументов на этапе компиляции и прерывать компиляцию с сообщением об ошибке, если указан неправильный формат. Тогда разработчик точно не сможет ошибиться.
Для C++23 в P2216R3 было предложено сделать именно это — и бэкпортировать исправление в C++20.
Улучшения получили std::ranges::split_view в P2210R2, std::ranges::join_view в P2328R1, да и вообще все std::ranges::view* в P2325R3
Теперь код с ranges компилируется и работает в большем количестве случаев, вместо того чтобы ругаться страшными непонятными словами. Например:
std::string_view s = "1.2.3.4";
auto ints =
s | std::views::split('.')
| std::views::transform([](auto v){
int i = 0;
// До P2210R2 тип переменной `v` был forward range, а
// соответственно никаких .size() и .data() у него не было.
std::from_chars(v.data(), v.size(), &i);
return i;
});
Но это не всё!
На подходе std::ranges::to, который позволит произвольный диапазон сохранять в произвольный контейнер:
std::list<std::forward_list<int>> lst = {{0, 1, 2, 3}, {4, 5, 6, 7}};
auto vec1 = lst | ranges::to<std::vector<std::vector<int>>>();
Чтобы std::ranges::to работал со всеми контейнерами стандартной библиотеки, в P1425R4 были добавлены недостающие конструкторы в std::stack и std::queue.
consteval int f(int i) { return i; }
constexpr int g(int i) {
if (std::is_constant_evaluated()) {
return f(i) + 1; // компилятор будет ругаться: "i не константа"
} else {
return 42;
}
}
constexpr auto value = g(1);
В C++23 провели работу над ошибками и добавили более могущественный инструмент if consteval:
consteval int f(int i) { return i; }
constexpr int g(int i) {
if consteval {
return f(i) + 1; // Теперь всё хорошо
} else {
return 42;
}
}
constexpr auto value = g(1);
У нас во фреймворке userver в Яндекс Go есть своя реализация RCU на Hazard Pointers. На редкость полезная и шустрая вещь, всем рекомендую попробовать стандартную реализацию, когда она появится (или, может, мы сначала успеем открыть userver).
Некоторые из этих идей мы активно обсуждаем на stdcpp.ru. Кстати, мы переехали на GitHub: github.com/cpp-ru/ideas/issues, чтобы вам было удобнее и привычнее. Присоединяйтесь, предлагайте свои улучшения для стандарта, беритесь за написание несложных предложений.
А ещё мы готовим новенькую конференцию C++ Zero Cost Conf — про высокую нагрузку и приложения, чувствительные к задержкам. Следите за анонсами в телеграм-чате.
Источник статьи: https://habr.com/ru/company/yandex/blog/561104/
Должен заметить, что международный комитет в онлайне работает совсем уж неторопливо… Настолько неторопливо, что на февральской встрече из полезного приняли только std::to_underlying() — функцию, преобразовывающую значение enum к нижележащему целочисленному типу:
enum class ABCD : std::uint64_t { A = 0x1012, B = 0x405324, };
constexpr std::uint64_t value = std::to_underlying(ABCD::A);
auto [ptr, count] = std::allocate_at_least(allocator, size)
Современные аллокаторы крайне сложны и не всегда делают именно то, о чём вы их просите. Предположим, вы пользуетесь jemalloc и напишете:std::vector<std::byte> data;
data.reserve(200);
Тогда аллокатор выделит память не под 200 байт, а под 224. Однако у std::vector до C++23 нет никакой возможности об этом узнать и использовать оставшиеся 24 байта (какое расточительство!). Из-за этого могли происходить лишние реаллокации. Например, если вы вставляли в вектор более 200, но менее 225 байт, то вектор мог реаллоцироваться на 400 байт (при этом аллокатор отдал бы нам памяти под 448 байт).
В C++23 добавили новый интерфейс, и теперь аллокаторы могут сообщать вам, под какое количество элементов была выделена память на самом деле. std::vector сможет использовать это из коробки. Ни одного байтика не пропадёт!
Полное описание предложения доступно в документе P0401R6.
std::spanstream
Радостная весть для всех, кто пользуется iostreams! В C++23 добавлены новые классы, позволяющие работать с массивами символов как с потоками, без лишних копирований и динамических выделений памяти:std::ispanstream isp{"10 20 30"};
int i;
isp >> i;
std::spanstream может работать с любыми символами, расположенными последовательно в памяти (другими словами, со всем, от чего можно сконструировать std::span).
Подробности и больше примеров можно найти в документе P0448R4.
Однако пользователей такого класса в C++23 ожидается не так много, потому что std::format_to был принят ещё в C++20 и обладает несколько большей производительностью. Кстати, о нём…
C++20 правки для std::format и std::format_to
Вот вам небольшой пример с std::format:auto s = std::format("{:d}", "I am not a number");
Скорее всего, разработчик допустил ошибку при написании этого кода и указал строку формата. При выполнении с текущим стандартом C++20 кинет исключение std::format_error.
Но можно сделать лучше — проверять описание формата и типы аргументов на этапе компиляции и прерывать компиляцию с сообщением об ошибке, если указан неправильный формат. Тогда разработчик точно не сможет ошибиться.
Для C++23 в P2216R3 было предложено сделать именно это — и бэкпортировать исправление в C++20.
std::ranges
Пока Ranges ещё не появились в стандартных библиотеках или их поддержка помечена как экспериментальная, комитет решил немного их переделать.Улучшения получили std::ranges::split_view в P2210R2, std::ranges::join_view в P2328R1, да и вообще все std::ranges::view* в P2325R3
Теперь код с ranges компилируется и работает в большем количестве случаев, вместо того чтобы ругаться страшными непонятными словами. Например:
std::string_view s = "1.2.3.4";
auto ints =
s | std::views::split('.')
| std::views::transform([](auto v){
int i = 0;
// До P2210R2 тип переменной `v` был forward range, а
// соответственно никаких .size() и .data() у него не было.
std::from_chars(v.data(), v.size(), &i);
return i;
});
Но это не всё!
На подходе std::ranges::to, который позволит произвольный диапазон сохранять в произвольный контейнер:
std::list<std::forward_list<int>> lst = {{0, 1, 2, 3}, {4, 5, 6, 7}};
auto vec1 = lst | ranges::to<std::vector<std::vector<int>>>();
Чтобы std::ranges::to работал со всеми контейнерами стандартной библиотеки, в P1425R4 были добавлены недостающие конструкторы в std::stack и std::queue.
if consteval
Для любителей метапрограммирования в C++20 добавили std::is_constant_evaluated(). Увы, он плохо справляется с передачей параметров из контекста constexpr в consteval функции:consteval int f(int i) { return i; }
constexpr int g(int i) {
if (std::is_constant_evaluated()) {
return f(i) + 1; // компилятор будет ругаться: "i не константа"
} else {
return 42;
}
}
constexpr auto value = g(1);
В C++23 провели работу над ошибками и добавили более могущественный инструмент if consteval:
consteval int f(int i) { return i; }
constexpr int g(int i) {
if consteval {
return f(i) + 1; // Теперь всё хорошо
} else {
return 42;
}
}
constexpr auto value = g(1);
Прочие мелкие, но заметные улучшения
- В P2186R2 убрали поддержку Grabage Collector, потому что в таком виде им всё равно никто не пользовался, он просто добавлял UB.
- Добавили вспомогательные RAII-классы для работы с C API: std:ut_ptr и std::inout_ptr в P1132R7.
- std::type_info:perator== теперь constexpr, что позволяет писать static_assert(typeid(x) == typeid);. Сам документ на редкость небольшой: P1328R1.
- Методы starts_with и ends_with теперь доступны не только для std::string и std::string_view, но и в виде отдельных алгоритмов в заголовочном файле algorithm.
- std::string_view теперь можно конструировать от contiguous-диапазона, все детали нового конструктора доступны в P1989R2.
- std:ptional и std::variant теперь более constexpr благодаря P2231R1.
- И наконец, приятный багфикс от Яндекса, запрещающий конструирование std::string_view и std::string от nullptr, предложение P2166R1. Ура, больше ошибок будет отлавливаться на этапе компиляции!
Concurrency TS
Маленькая, но радостная новость для любителей многопоточности и lock-free. Готовится к выходу Concurrency TS — экспериментальное многопоточное API для последующего включения в стандарт. В нём нас ждут P1121R3 Hazard Pointers и P1122R4 Read-Copy-Update (RCU).У нас во фреймворке userver в Яндекс Go есть своя реализация RCU на Hazard Pointers. На редкость полезная и шустрая вещь, всем рекомендую попробовать стандартную реализацию, когда она появится (или, может, мы сначала успеем открыть userver).
Вместо итогов
На подходе в C++23 действительно большие и интересные вещи — flat-контейнеры, unique_function, работающий с агрегатами std::get, constexpr to_chars и даже получение std::stacktrace из любого пойманного исключения.Некоторые из этих идей мы активно обсуждаем на stdcpp.ru. Кстати, мы переехали на GitHub: github.com/cpp-ru/ideas/issues, чтобы вам было удобнее и привычнее. Присоединяйтесь, предлагайте свои улучшения для стандарта, беритесь за написание несложных предложений.
А ещё мы готовим новенькую конференцию C++ Zero Cost Conf — про высокую нагрузку и приложения, чувствительные к задержкам. Следите за анонсами в телеграм-чате.
Источник статьи: https://habr.com/ru/company/yandex/blog/561104/