воскресенье, 22 сентября 2019 г.

C++ Russia 2019 (Москва)

Подборка докладов с конференции, которые стоит посмотреть в записи на ютубе.

Nicolai Josuttis - C++17 — the biggest traps

Nicolai Josuttis рассказал про:
1. Различные способы инициализации переменных в С++.
2. Показал примеры использования filesystem в С++ 17.
3. Различные варианты использования constexpr, включая if constexpr
4. Fold expressions - полезнейшая фича, которая появляется в С++ 17.
5. Особенности использования string_view.
6. Использование параллельных алгоритмов с std::execution::par
7. std::optional и std::variant.
8. CTAD (Class template argument deduction) и deductions guides
Ждем с нетерпением книгу C++17 - The Complete Guide by Nicolai M. Josuttis (http://www.cppstd17.com/).

Олег Фатхиев - Эволюция метапрограммирования: как правильно работать со списками типов

Автор в своем докладе начал с простых примеров использования метапрограммирования и закончил метафункциями, которые по заданной лямбде фильтруют или выполняют другие операции над списками типов.
Понравилось то, что он в каждом примере приводил три варианта решения:
1. Простой с использованием классических средств метапрограммирования, которые были доступны еще до С++ 11. Например, рекурсия для прохода по списку типов.
2. Улучшенный с использование variadic templates и sizeof...
3. Самый лучший с использованием fold expressions и возможностей constexpr, который появились в С++ 17. В этом варианте получался наиболее красивый и лаконичный код.
Также докладчик продемонстрировал интересные приемы с использованием std::index_sequence.

Know your hardware: CPU memory hierarchy - Alexander Titov

Интересный доклад, в этот раз он был на английском, но при желание можно посмотреть его видеозапись на русском с конфы corehard (https://www.youtube.com/watch?v=rBMN_yyzi18).
Из интересных моментов можно выделить следующие:
- Не забывать про принцип локальности данных.
- Принудительная упаковка - это зло. Например, если в структуре, для которой включена принудительная упаковка (pragma pack), присутствует atomic<uint64_t>, и так совпало, что это поле оказалось на границе сразу двух 64-байтовых линий кеша процессора, то это может вызвать замедление в 300 раз. Если принудительная упаковка не включена, то такое никогда не произойдет, так как компилятор позаботится о том, чтобы атомик целиком поместился на одну кеш линию.
- Не допускайте, чтобы данные с которыми работают разные потоки оказывались в одной линии. Это также приведет к замедлению, а точнее к отсутствию ускорения, на которое расчитывал автор, добавляя потоки. Например, есть массив int thread_results[4], в который периодически пишут 4 потока, каждый в свою ячейку. Так как все 4 элемента массива скорее всего попадут в одну кеш линию, то это будет проблемой.
- По возможности следует отделять горячие данные, с которыми вы работаете часто, от холодных данных, которые используются редко. Например, есть структура Mixed { int warm; int cold[15]; }, и есть какой-то большой массив таких структур, с которым работает ваш алгоритм. При этом алгоритм постоянно обращается к полю warm и лишь изредка к полю cold. В этом случае кеши процессора используются крайне не эффективно, так как в кеш то и дело попадают данные cold, которые не используются. Как вариант, эти данные можно было бы разделить, т.е. сделать отдельный массив, в которым лежали бы только данные warm, и отдельный массив для данных cold.
- Докладчик порекомендовал почитать по этой теме: intel architectures optimization reference manual
- А также посмотреть курс: high-performance computing and concurrency

Шаблоны C++ и базы данных - Сергей Федоров

Доклад получился на удивление годным. Докладчик на реальном примере из практики показал, как if constexpr (C++ 17) помогает упростить код и сделать его более лаконичным, избавившись от разных устаревших практик, таких как, например, Tag Dispatching.
Также продемонстрировал много интересных примеров создания метафункций для своей системы трейтов.
На следующем примере трейта показал, как определять, есть ли у типа T реализация в точке использования трейта:
namespace detail{
template<typename T, std::size_t sizeof(T)>
std::true_type IsCompleteImpl(T*);
std::false_type IsCompleteImpl(...);
}
template<typename T>
using IsDeclComplete = decltype(detail::IsCompleteImpl(std::declval<T*>()));

Здесь фокус в том, что для типа T можно работать с его указателем и даже получать от него declval, если у типа нет реализации. Однако без реализации нельзя получить sizeof.
Также докладчик показал хорошие примеры использования std::index_sequence и fold expressions.