- PVSM.RU - https://www.pvsm.ru -
В начале июня в городе Рапперсвил-Йона завершилась встреча международной рабочей группы WG21 по стандартизации C++.
Вот что вас ждёт под катом:
Так же будет бонус: мини секция для экспертов:
В C++20 приняли контракты. А значит можно будет в скором времени забыть про использование макросов для ассертов, получить лучшую документацию из коробки и даже заметить прирост производительности. Выглядят контракты на практике вот так:
std::string get_name_by_login(std::string_view login)
[[expects: !login.empty() ]]
[[ensures ret_value: !ret_value.empty() ]]
;
В описании выше, всё что в двойных квадратных скобках, является контрактами. Так вот, из них:
Подробности по контрактам доступны в официальной бумаге [1].
На помощь контрактам спешит библиотека от РГ21 [2] и Fails [3], позволяющая сохранять и печатать стектрейс. Так можно будет задать обработчик проваленного контракта и печатать в нём последовательность вызовов, которая привела к проблеме:
void(const std::contract_violation & e) noexcept {
std::cerr << "Contract violated in function " << e.function_name() << 'n'
<< std::stacktrace();
}
При нарушении контракта, мы увидим подобное сообщение:
Contract violated in function std::array<T, N>::operator[](size_type) [with T = int; long unsigned int N = 5ul; ]':
0# std::array<int, 5ul>::operator[](unsigned long) at /usr/include/c++/array:124
1# bar(int) at ../example/assert_handler.cpp:17
2# foo(int) at ../example/assert_handler.cpp:25
3# main at ../example/assert_handler.cpp:54
4# 0x00007F991FD69F45 in /lib/x86_64-linux-gnu/libc.so.6
5# 0x0000000000401139
}
std::stacktrace ещё не принят в C++20, но прошёл design review в группе LEWG и осталась только работа по приведению его описания в соответствие с правилами стандарта в группе LWG. Последняя спецификация доступна по ссылке [4].
Концепты, как фича языка, были уже приняты на прошлом заседании комитета [5], а в этот раз в стандартную библиотеку приняли основные концепты из Ranges TS. Так что теперь можно пользоваться готовыми концептами для описания compile-time требований к шаблонным параметрам и не мучатся с написанием собственных:
template <class F>
requires Invocable<F>
void my_executor::execute(F f) noexcept {
lock_guard l{data_mutex_};
push(std::move(f));
}
Полный список концептов и их описания доступны в этом proposal [6].
Уже длительное время компиляторы и стандартные библиотеки предоставляют макросы, для описания возможностей компилятора. Теперь эти макросы официально являются частью стандарта и даже были расширены. Так теперь можно проверить поддержку компилятором аттрибута unlikely используя выражение __has_cpp_attribute(unlikely).
Список макросов принятых на заседании доступен в бумаге [7].
Использование reinterpret_cast для преобразования одного тривиально копируемого типа в другой — очень плохая идея. Но искушение велико и многие разработчики это делают. Поэтому комитет C++ сделал функцию специально для таких случаев.
Использовать её легко, просто замените
my_type my = reinterpret_cast<my_type&>(some_array);
на
my_type my = std::bit_cast<my_type>(some_array);
Теперь, если размеры some_array и my_type не совпадают, или если вы пытаетесь преобразовать не тривиально копируемые типы — вы получите сообщение об ошибке на этапе компиляции. В остальных случаях — вы избежите всех страшных ошибок связанных с type aliasing.
Вот некоторые полезные вещи, добавленные в стандартную библиотеку C++20:
В добавок, уже имеющиеся алгоритмы использующие std::swap и сам std::swap стали constexpr. Так что теперь можно сортировать, вызывать std::nth_element и получать их результаты на этапе компиляции. Все подробности доступны в бумаге [8] от РГ21.
Вы работаете со структурами данных в основном из одного потока, но в какой-то момент вам необходимо работать с полем атомарно? Для этих случаев был добавлен шаблонный класс atomic_ref<T> (формальное описание доступно в бумаге [9]).
При этом надо помнить, что атомарность гарантируется только для операций производимых через экземпляры классов atomic_ref<T>. Так что если вы в одном потоке пишете в переменную без atomic_ref, а в другом потоке читаете через atomic_ref — то в итоге ничего хорошего не получится.
Кстати, если вам не нравятся неконсистентные имена типов (string_view, atomic_ref), то выскажите своё недовольство по ссылке [10]. Если будет достаточное количество голосов, постараемся все имена привести к одному виду.
Если вы написали класс X, и для него написали operator<=> следующего вида:
struct X {
// ...
std::strong_equality operator<=>(const X&, const X&) = default;
// ...
};
То ваш класс можно будет использовать в качестве шаблонного параметра:
template <X x>
struct x_as_template_param {
// ...
};
Однако комитету ещё предстоит большая работа по модернизации стандартной библиотеки и переводу различных её частей на использование operator<=>.
Ограничения для функций, выполняемых на этапе компиляции, были ослаблены и теперь можно писать классы с constexpr виртуальными функциями.
При этом если в базовом классе у вас имеется метод constexpr virtual int foo();, то в наследнике int foo() может быть как constexpr, так и нет. При вызове foo() на этапе компиляции компилятор не даст вам скомпилировать программу, если вы будете пытаться выполнить не constexpr виртуальную функцию.
Данное изменение, например, открывает двери для реализации применимого на этапе компиляции std::type_info, что позволит этому классу получить функционал Boost.TypeIndex [11], с возможностью гарантированной compile-time работы с типами:
template <class T, class U>
constexpr bool is_same() {
constexpr bool res = (typeid(T) == typeid(U));
return res;
}
Последние подробности доступны в бумаге [12].
Parallelism 2 всё ещё готовится к выходу, подробности и крутые фишечки можно посмотреть в прошлом посту [13]. С момента прошлого поста немного поправили type traits связанные с simd да добавили функционала для векторных инструкций.
Reflection готовится к выпуску в виде технической спецификации (TS). В нём рефлексия делается всё ещё через механизмы схожие с <type_traits>. В планах донести до ядра языка больше функционала для constexpr вычислений и переделать рефлексию на constexpr! функции (см. ниже).
Executors в C++20 скорее всего не попадут. Скорее всего они будут выпущены в виде отдельного TS. Возможно что весь их дизайн будет пересмотрен и упрощён.
Изменение, которое должно попасть в C++20 (на следующем заседании) повлияет на производительность различных частей стандартной библиотеки и оптимизации компиляторов, но вряд ли будет заметно в повседневной разработке:
struct i_am_trivial {
int foo;
char bar;
virtual ~i_am_trivial() = default;
};
Идея в том, что если деструктор виртуальный, это ещё не значит что он не тривиальный. Так стандартная библиотека сможет понимать, что тип с которым она работает хоть и имеет виртуальный деструктор, на самом деле не требует вызова деструктора для освобождения ресурсов. Это может дать прирост производительности например для std::vector<Base>, где Base имеет такой виртуальный деструктор.
Ещё одно занятное изменение, которое рассматривается для приёма в C++20 — это constexpr! функции.
Такие функции обязаны выполняться только на этапе компиляции, любая попытка использовать их в runtime приведёт к ошибке компиляции. Это одно из изменений необходимых для рефлексии в C++.
Дополнительным бонусом constexpr! функций является их эффективное использование ресурсов компилятора. Т.к. constexpr! функции не выполняются на рантайме, компилятор не должен генерировать промежуточное представление (машинные инструкции) для них и не должен держать их памяти или оптимизировать. Это резко уменьшает количество оперативной памяти, требуемой компилятору и несколько ускоряет компиляцию. Должно оказывать ощутимый эффект на современные библиотеки, сильно полагающиеся на метапрограммирование, как Boost.Hana [14] или [Boost.]PFR [15].
Множество языков программирования в данный момент компилируют/транслируют регулярные выражения ещё перед запуском программы. Таким образом, когда программа стартует, все регулярные выражения уже преобразованы в соптимизированный конечный автомат.
В C++ это не так:
bool is_valid_mail(std::string_view mail) {
static const std::regex mail_regex(R"((?:(?:[^<>()[].,;:s@"]+(?:.[^<>()[].,;:s@"]+)*)|".+")@(?:(?:[^<>()[].,;:s@"]+.)+[^<>()[].,;:s@"]{2,}))");
return std::regex_match(
std::cbegin(mail),
std::cend(mail),
mail_regex
);
}
В коде выше конечный автомат из регулярного выражения будет строится при первом заходе в функцию is_valid_mail(). Это долгая операция, которая в добавок будет выполняться в критической секции.
С готовящимися новинками для constexpr вычислений (constexpr new, is_constexpr_evaluated() и др.) можно будет в C++ делать множество вещей на этапе компиляции, в том числе можно будет сделать constexpr std::regex.
С constexpr std::regex конечный автомат для функции is_valid_mail() построится ещё на этапе компиляции. Более того, GCC сможет генерировать оптимизированные регулярки на этапе компиляции без static const, т.к. начиная с GCC-6 если у constexpr функции все параметры на вход — константы, GCC форсирует вычисление на этапе компиляции.
Так вот, как вам идея сделать constexpr std::regex [16]?
P.S.: Для желающих денег C++ практики, с недавнего времени есть Yandex.Taxi Coding Fest [17]. Можно будет вооружиться и побеждать соперников используя C++17.
Автор: antoshkka
Источник [18]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/285137
Ссылки в тексте:
[1] в официальной бумаге: https://wg21.link/p0380
[2] РГ21: https://stdcpp.ru/
[3] Fails: https://habr.com/users/fails/
[4] по ссылке: https://wg21.link/p0881
[5] прошлом заседании комитета: https://habr.com/company/yandex/blog/336264/
[6] этом proposal: https://wg21.link/p0898
[7] доступен в бумаге: https://wg21.link/p0941
[8] в бумаге: https://wg21.link/p0879
[9] в бумаге: https://wg21.link/p0019
[10] по ссылке: https://stdcpp.ru/proposals/679c607b-2637-44ff-8750-3819f7136a79
[11] Boost.TypeIndex: https://www.boost.org/doc/libs/1_67_0/doc/html/boost_typeindex/examples.html#boost_typeindex.examples.c_14_checking_namespace_at_compi
[12] в бумаге: http://wg21.link/p1064
[13] прошлом посту: https://habr.com/company/yandex/blog/351492/
[14] Boost.Hana: https://github.com/boostorg/hana
[15] [Boost.]PFR: https://github.com/apolukhin/magic_get
[16] как вам идея сделать constexpr std::regex: https://stdcpp.ru/proposals/801b1630-9cdd-4a1c-ab85-28d24759e8c4
[17] Yandex.Taxi Coding Fest: https://taxi.yandex.ru/action/ytcf/coding_fest
[18] Источник: https://habr.com/post/413719/?utm_campaign=413719
Нажмите здесь для печати.