- PVSM.RU - https://www.pvsm.ru -
На днях прошла встреча международного комитета по стандартизации C++ в Кёльне. В прошлый раз был принят feature freeze на C++20, так что комитет должен был обсуждать только исправления уже принятых вещей, а добавлять новинки уже в C++23…
… но всё было не так!
Что сделали с std::flat_map; останутся ли страшные ключевые слова co_return, co_await и co_yield; успели ли доделать std::format; в каком виде будут контракты в C++20? Всё это вас ждёт под катом.
День был насыщенным — решили переименовать все концепты в snake_case вместо CamelCase. Вдобавок с большим перевесом по голосам приняли предложение P1607 [1], которое меняет синтаксис и поведение контрактов на более понятное (но также требующее макросов).
Обсуждали корутины. Отклонили всё, включая наше предложение на отбрасывание co_ с ключевых слов для корутин [2]. Увы.
Внезапно сообразили, что одобренное в понедельник предложение P1607 [1] никто на практике не проверял, обсуждалось оно минут 30, в то время как существующее решение на контракты оттачивалось в течение многих лет.
После длительного обсуждения решили, что контракты в принципе не готовы к C++20. И убрали их из стандарта.
Обсуждали вещи для C++23. Основные силы были сосредоточены на новых механизмах в обработке ошибок. Были как общие размышления [3] на тему, так и конкретные предложения на новый спецификатор исключений throws [4].
В комитете есть подгруппа LWG. Любой документ, добавляющий функциональность в стандартную библиотеку, должен пройти ревью в этой подгруппе.
Средняя пропускная способность LWG — ~30 документов в неделю. В Кёльне надо было рассмотреть более 50 документов, среди которых около половины крайне внушительных размеров, например:
* std::flat_map [5]
* std::jthread [6]
* operator<=> для стандартной библиотеки [7]
* Новые примитивы синхронизации [8]
+ из EWG прилетела бумага на переименование концептов в snake_case.
#include <type_traits>
template<typename T>
struct Optional {
// ...
~Optional() requires(std::is_trivially_destructible_v<T>) = default;
~Optional() requires(!std::is_trivially_destructible_v<T>) {
if (inited_) reinterpret_cast<T&>(data_).~T();
}
private:
bool inited_{false};
std::aligned_storage_t<sizeof(T), alignof(T)> data_;
};
template <class F>
[[nodiscard("Without storing the result the code executes synchronously")]] future async(F&& );
auto test() {
// ...
// warning: Without storing the result the code executes synchronously
async([huge_data](){
std::cerr << huge_data;
});
}
enum class rgba_channel { kRed, kGreen, kBlue, kAlpha};
std::string_view to_string(rgba_channel channel) {
using enum rgba_channel;
switch (channel) {
case kRed: return "red";
case kGreen: return "green";
case kBlue: return "blue";
case kAlpha: return "alpha";
}
}
template <typename T>
struct S {
T x;
T y;
};
S t{'4', '2'}; // Deduces `S<char>`
void f(int(&)[]); // p.s.: надеюсь такой код не пишут без крайней необходимости
int arr[1];
f(arr); // OK
int count_invocations() {
// Программа не соберётся, если компилятор попытается
// инициализировать переменную `counter` на рантайме.
//
// Другими словами - появился инструмент, позволяющий убедиться
// что комиплятор не вставит лишние атомарные инструкции для защиты
// `counter` от конкурентной инициализации.
static constinit std::atomic<int> counter{0};
return ++counter;
}
struct [[nodiscard]] my_scopeguard { /* ... */ };
struct my_unique {
[[nodiscard]] my_unique(int fd) { /* ... */ } // захватывает ресурс во владение
/* ... */
};
void sample() {
my_scopeguard(); // warning
void(my_scopeguard()); // cast к void, warning не появится
my_unique(42); // warning
}
constexpr auto birthday = 28d/April/1989;
string s = format("At {0:%d} of {0:%B}, {0:%Y} someone was born", birthday);
assert(s == "At 28 of April, 1989 someone was born");
#include <atomic>
enum class States {
kInitial, kProcessing, kPosting,
};
// Фу! Глобальная переменная!
std::atomic<States> state{States::kInitial};
void state_machine_do_posting() {
for (;;) {
States expected_state = States::kProcessing;
// Ждем пока другой поток выставит состояние в kProcessing
state.wait(expected_state);
if (!state.compare_exchange_strong(expected_state, States::kPosting)) {
continue;
}
// do something
}
}
std::string to_string(const MyType& v) {
std::string buf;
constexpr std::size_t kMaxSize = 32;
buf.reserve(kMaxSize);
// До C++20 копировало строчку, в C++20 — принимает во владение
std::ostringstream oss{std::move(buf)};
oss << "MyType{" << v << '}';
// До C++20 копировало строчку, в C++20 — извлекает
return std::move(oss).str();
}
#include <thread>
void sample() {
bool ready = false;
std::mutex ready_mutex;
std::condition_variable_any ready_cv; // нужен именно `_any`!
std::jthread t([&ready, &ready_mutex, &ready_cv] (std::stop_token st) {
while (!st.stop_requested()) {
/* ... */
{
std::unique_lock lock{ready_mutex};
// Ждёт нотификации и ready == true, или stop_token.request_stop(),
// или jthread.request_stop().
ready_cv.wait_until(lock, [&ready] { return ready; }, st);
}
/* ... */
}
});
/* ... */
// Деструктор `t` вызовет request_stop() и будет ждать пока лямбда не завершится.
}
В итоге был найден пример, где рефлексия косячит [34]. Как итог, в документе от Лизы Липпинкотт на новые type_traits есть занятное введение:
Over dinner at CppCon, Marshall Clow and I discussed a bit of code that relied on two types being layout-compatible. As it happened, the types weren’t layout-compatible after all. I opined that there should be a way to statically assert layout-compatibility, so that the error would be caught at compile time, rather than dinner time. Marshall replied, “Write a proposal.” This is that proposal.
Увы, std::stacktrace, std::flat_map, std::flat_set в C++20 не попали :(
Началась работа над крупными вещами, включая адаптацию Boost.Process для стандарта, переосмысливание работы с файлами и вводом/выводом, линейную алгебру, юникод, 2d графика, аудио, JIT компиляцию C++ кода.
Большая часть вещей будет ещё претерпевать крупные изменения. Ближе всего к принятию std::filesystem::path_view [37]. path_view позволит работать с путями без динамических аллокаций, что является первым шагом к сверхпроизводительной работе с файловой системой.
Как и всегда, мы работали в различных подгруппах, чинили баги, правили тексты, делились опытом по внедрению, презентовали бумаги, авторы которых не смогли приехать. Так, например, в последний момент заметили и подправили работу std::format с Inf/NaN; убрали неожиданности из интерфейса jthread; протащили через одну из подгрупп предложение на хеширование pair, tuple, string, array [38].
Много времени провели в подгруппе SG1 Concurrency за обсуждением conscurrent_unordered_map. В итоге функции visit теперь не будут защищать переданный value от конкурентной модификации, только от удаления из контейнера:
concurrent_unordered_map<int, std::string> conc_map;
conc_map.visit(42, [](std::string& value) { // да, неконстантная ссылка....
// Раньше было всегда OK. Теперь OK если другие визиторы не меняют это же value.
std::cerr << value;
// Раньше было всегда OK. Теперь OK если другие визиторы не меняют это же value.
value += "Hello";
});
.
С таким интерфейсом проще стрелять себе в ноги выжать максимум производительности для некоторых статистических задач, при этом синхронизация фактически ложится на плечи пользователя:
concurrent_unordered_map<int, std::atomic<int>> conc_map;
conc_map.visit(42, [](std::atomic<int>& value) { // да, неконстантная ссылка....
// Всегда OK
++ value;
});
Так же есть небольшие подвижки в SG6 Numerics — начали думать над Numerics TS с большим количеством новых классов чисел, в том числе с wide_integer от нас.
Осенью в Питере состоится конференция C++ Piter [39], на которой можно будет лично пообщаться со многими людьми из комитета.
Встреча РГ21 по итогам Кёльнского собрания ISO стоитоится 9 августа (регистрация [40] обязательна, количество мест ограничено). На встрече можно задать вопросы об интересующих вас новинках и узнать побольше о C++20 и C++23.
Автор: Antony Polukhin
Источник [41]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/325365
Ссылки в тексте:
[1] P1607: https://wg21.link/p1607
[2] отбрасывание co_ с ключевых слов для корутин: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1485r1.html
[3] общие размышления: https://wg21.link/p1095r0
[4] новый спецификатор исключений throws: https://wg21.link/p0709r3
[5] std::flat_map: https://wg21.link/P0429
[6] std::jthread: https://wg21.link/P0660
[7] operator<=> для стандартной библиотеки: https://wg21.link/P1614
[8] Новые примитивы синхронизации: https://wg21.link/P1135
[9] в constexpr теперь не обязательно нуль-инициализировать каждую переменную: https://wg21.link/p1331
[10] requires теперь можно использовать для конструкторов и деструкторов.: http://wg21.link/p0848
[11] [[nodiscard]] обзавёлся диагностическим сообщением: http://wg21.link/p1301
[12] using enum: https://wg21.link/p1099
[13] Deduction guides для агрегатов заработали из коробки: http://wg21.link/p1816
[14] __asm директивы теперь могут появляться в constexpr функциях: http://wg21.link/p1668
[15] Массивы заданного размера теперь можно приводить к размерам неизвестного размера: https://wg21.link/p0388
[16] constinit: https://wg21.link/p1143
[17] правила: https://wg21.link/p1452
[18] случаи использования volatile теперь deprecated: https://wg21.link/p1152
[19] на конструкторы и целые классы: https://wg21.link/p1771
[20] начал работать для алиасов: https://wg21.link/p1814
[21] std::vector и placement new теперь можно использовать в constexpr: https://wg21.link/p0784
[22] <bit> с большим количеством полезных битовых операций: https://wg21.link/p0553
[23] <format> с замечательным набором функций для форматирования строк: https://wg21.link/p0645
[24] chrono и locale: https://wg21.link/p1361
[25] более аккуратную поддержку float: https://wg21.link/p1652
[26] constexpr для bind, invoke, reference_wrapper: https://wg21.link/p1065
[27] Заголовочный файл <numbers> с математическими константами: http://wg21.link/p0631
[28] операторы были: https://wg21.link/p1614
[29] дополнительными методами: https://wg21.link/p0408
[30] Новый класс для запуска нового потока выполнения: https://wg21.link/p0660
[31] два разных типа данных имеют одинаковое внутреннее представление: https://wg21.link/p0466
[32] antoshkka: https://habr.com/ru/users/antoshkka/
[33] о рефлексии без макросов и кодогенерации в C++14: https://youtu.be/abdeAew3gmQ
[34] был найден пример, где рефлексия косячит: https://github.com/apolukhin/magic_get/blob/8bb5eb2f33fbc360610de3759549f07baa31b3a6/test/flat/core.cpp#L336-L360
[35] std::source_location: https://wg21.link/p1208
[36] Выкинули: https://wg21.link/p1661
[37] std::filesystem::path_view: https://wg21.link/p1030
[38] хеширование pair, tuple, string, array: https://wg21.link/p1406
[39] C++ Piter: https://cppconf-piter.ru/
[40] регистрация: https://events.yandex.ru/events/cpp-party/09-aug-2019/?utm_source=habr&utm_content=post290719
[41] Источник: https://habr.com/ru/post/458938/?utm_source=habrahabr&utm_medium=rss&utm_campaign=458938
Нажмите здесь для печати.