В начале марта в американском городе Джексонвилле завершилась встреча международной рабочей группы WG21 по стандартизации C++. На встрече добавляли фишки в C++20, подготавливали к выпуску «превью» новых компонентов и полировали до блеска шероховатости языка.
Хотите посмотреть на новости и узнать:
- Почему это тут золотая медаль справа?
- Как там поживает кросплатформенный SIMD?
- Что будет если 4000 поделить на последнюю пятницу февраля?
- Какие подводные камни нашлись у сопрограм?
- Какие крутые фишки для многопоточного программирования будут в скором времени доступны?
Календари и временные зоны
Смотрите как красиво и легко теперь можно задавать даты в C++20:
using std::chrono;
year_month_day ymd = 2016y/May/29d; // 2016-05-29
Нужно работать ещё и с миллисекундами, да ещё и в часовом поясе Токио? Без проблем:
auto tp = sys_days{ymd} + 7h + 30min + 6s + 153ms; // 2016-05-29 07:30:06.153 UTC
zoned_time zt = {"Asia/Tokyo", tp};
cout << zt << 'n'; // 2016-05-29 16:30:06.153 JST
Есть инструменты для работы с международным атомным временем, разбором времён из строки, экзотические типы данных позволяющие хранить даты «вторая пятница февраля», «вторая неделя» или «вторая неделя марта». и т.п.
Так что теперь можно получить дату последней пятницы февраля 4000 года:
auto last_friday_feb = February/Friday[last];
std::cout << 4000 / last_friday_feb << std::endl;
Черновое описание всех возможностей доступно вот тут.
Span
Если вам нравится std::string_view из C++17 (или boost::string_view/boost::string_ref), то std::span вам тем более понравится!
Представьте себе, что у вас есть шаблонная функция, что-то делающая с массивом int:
void do_something(int* p, size_t size);
Чтобы вызвать этот метод нужно достаточно много писать:
std::vector<int> v;
do_something(v.data(), v.size());
int data[1024];
do_something(data, std::size(data));
boost::container::small_vector<int, 32> sm;
do_something(sm.data(), sm.size());
Другой минус — внутри такого метода неудобно работать с алгоритмами стандартной библиотеки + не будет работать range based for:
void do_something(int* p, size_t size) {
std::sort(p, p + size);
for (size_t i = 0; i < size; ++i) {
p[i] += p[0];
}
}
Так вот, std::span — это класс, который хранит указатель и размер массива данных (при том размер порой не хранится, а используется информация, доступная на этапе компиляции). С этим новым классом код становится несколько проще и без указателей:
void do_something(std::span<int> p) {
std2::sort(p);
for (int& v: p) {
v += p[0];
}
}
// ...
std::vector<int> v;
do_something(v);
int data[1024];
do_something(data);
boost::container::small_vector<int, 32> sm;
do_something(sm);
Описание std::span доступно в pdf.
typename? Забудьте о нём в C++20!
Если вы путались, когда надо ставить typename, а когда – не надо, то у меня для вас хорошие новости! Начиная с C++20 в подавляющем большинстве мест можно будет не писать typename:
template<class T> T::R f();
template<class T> struct S {
using Ptr = PtrTraits<T>::Ptr;
T::R f(T::P p) {
return static_cast<T::R>(p);
}
auto g() -> S<T*>::Ptr;
};
Новые атрибуты
- [[no_unique_address]] — если пометите этим аттрибутом переменную класса, то компилятор сможет более агрессивно оптимизировать её расположение в памяти. Например, может в принципе не выделять под неё место.
- [[likely]] — помечаете им выражение (например `if (flag){ [[likely]] std::cout << «OK»; }` ) или case от switch, и компилятор начинает оптимизировать код, считая, что помеченная ветка будет выполняться чаще, чем другие.
- [[unlikely]] — подсказывает компилятору, что в это место мы редко попадаем на рантайме.
Сonstexpr метапрограммирование
Внезапная прорывная новость – комитет предварительно одобрил бумагу о использовании std::allocator в constexpr выражениях. Предстоит ещё огромное количество работы, но оптимистичный прогноз – получить к C++20 std::vector и std::string, которые можно использовать в выражениях на этапе компиляции. Это позволит компиляторам лучше оптимизировать, позволит использовать привычные всем контейнеры для рефлексии, метапрограммирования и метаклассов.
Работа в этом направлении продвигается не так быстро, как хотелось бы. Но, тем не менее, на встрече окончательно одобрили бумагу от РГ21 о добавлении «constexpr iterator», что позволит требовать от контейнера итераторов, применимых на этапе компиляции. Другую нашу бумагу на constexpr тему рассмотреть не успели.
Если кто еще не видел рассказ о метаклассах, рефлексии и людях, развивающих эти направления, то рекомендую посмотреть Herb Sutter “Meta: Thoughts on generative C++”.
Новые примитивы для многопоточности и векторных вычислений
Готовится к публикации «Parallelism 2 TS». Самыми интересными вещами, на мой взгляд, является тип данных для SIMD вычислений, благодаря которому можно писать оптимизированный кроссплатформенный код. В зависимости от платформы под капотом будет использоваться различный набор векторых инструкций (SSE, AVX, NEON, MDMX и т.п.):
void compute_on_aligned_data(float* data, size_t N) {
size_t i = 0;
for (; i + native_simd<float>::size() <= N; i += native_simd<float>::size()) {
native_simd<float> v(data + i, vector_aligned);
where(v > 100.f, v) = 100.f + (v - 100.f) * 0.1f;
v.copy_to(data + i, vector_aligned);
}
for (; i < N; ++i) {
float x = data[i];
if (x > 100.f) {
x = 100.f + (x - 100.f) * 0.1f;
}
data[i] = x;
}
}
Подробности по SIMD доступны в черновике предложения.
Остальные новинки параллелизма (включая примитивы для fork based параллелизма, новые многопоточные алгоритмы, тип данных для сохранения набора одновременно возникших исключений и т.п.) доступны в черновике.
Прочее
Огромное количество времени комитет занимался обсуждением больших новинок.
Сопрограммы
Добавляли функциональность для симметричных сопрограм, просмотра параметров в promise. Длительное время обсуждали проблемы, на которые наталкивались пользователи сопрограм. Так, например, следующий достаточно невинный код ведёт к падению приложения:
future<std::string> concat(const std::string& prefix, future<std::string> suffix) {
co_return (prefix + co_await suffix);
}
Модули
Решали проблемы, возникающие при их имплементации. Упрощали их использование. Ничего прорывного, полёт нормальный.
Reflection TS
Начали формировать новый TS для рефлексии. В основе него пока что находится вот это предложение. Выпущено в свет будет ещё не скоро.
Премия Дрейпера и Оскар
Помимо новостей, напрямую связанных с развитием языка C++, есть ещё новости на смежные темы.
Так Бьёрн Страуструп получил престижную премию Дрейпера за развитие языка C++. На что Бьёрн сказал, что это заслуга всей WG21, и для всех участников закатил банкет.
К другим новостям. О C++ теперь знают актёры Голливуда. При получении Оскара создатель Houdini, популярной программы для графических эффектов, поблагодарил разработчиков языка C++ за C++11.
Вместо итогов
Следующее собрание комитета будет летом. Если вы хотите что-то изменить в C++ или предложить свою идею, то всегда можете написать на https://stdcpp.ru/, где люди из РГ21 помогут вам донести ваши желания до комитета.
Желаете поговорить с нами вживую? Ищите нас на апрельской конференции C++ Russia в Питере.
Хотите пообсуждать C++ с другими разработчиками? К вашим услугам телеграм чат для новичков и чат для матёрых разработчиков, знающих разницу между memory_order_relaxed и memory_order_seq_cst.
Расскажите в комментариях, чего вы больше всего ждёте от C++20 и что из новинок кажется вам наиболее полезным.
Автор: antoshkka