C++20 всё ближе. Встреча в Джексонвилле

В начале марта в американском городе Джексонвилле завершилась встреча международной рабочей группы WG21 по стандартизации C++. На встрече добавляли фишки в C++20, подготавливали к выпуску «превью» новых компонентов и полировали до блеска шероховатости языка.

Хотите посмотреть на новости и узнать:
5-hrya3w3ig1qw3dmyvksxlzrbw.jpeg

  • Почему это тут золотая медаль справа?
  • Как там поживает кросплатформенный 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 v;
do_something(v.data(), v.size());

int data[1024];
do_something(data, std::size(data));

boost::container::small_vector 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 p) {
    std2::sort(p);
    for (int& v: p) {
        v += p[0];
    }
}
// ...
std::vector v;
do_something(v);

int data[1024];
do_something(data);

boost::container::small_vector sm;
do_something(sm);


Описание std: span доступно в pdf.

typename? Забудьте о нём в C++20!


Если вы путались, когда надо ставить typename, а когда — не надо, то у меня для вас хорошие новости! Начиная с C++20 в подавляющем большинстве мест можно будет не писать typename:


template T::R f();

template struct S {
    using Ptr = PtrTraits::Ptr;

    T::R f(T::P p) {
        return static_cast(p);
    }

    auto g() -> S::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::size() <= N; i += native_simd::size()) {
        native_simd 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​​ ​concat​(const​ std::string​& ​ prefix​, future​​ 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 и что из новинок кажется вам наиболее полезным.

© Habrahabr.ru