В докладе будут затронуты принципиальные вопросы — зачем нам программировать на шаблонах, как мы это делаем в C++11/14 и как будем это делать в C++17. Проведем параллель с функциональными языками (привет Haskell!). На примере реального кода разберем fold-expressions и увидим, чем опасен constexpr-if. А также взглянем на метапрограммирование в стиле C++11/14 и C++17 глазами компилятора.
Догнать и перегнать boost::lexical_castRoman Orlov
Разбор нестандартной реализации преобразования целого числа в строку без использования циклов и рекурсивных вызовов времени исполнения - только рекурсия на этапе компиляции
Фитнес для вашего кода: как держать его в формеIlia Shishkov
C++ Россия 2017
Во время моего выступления мы поговорим о принципе "Minimize coupling, maximize cohesion". Обсудим, что это такое и что значат эти непонятные слова. Кроме того на приближенном к реальности примере мы рассмотрим, как, применяя указанный принцип, можно держать ваш код в форме, чтобы он был готов ко всем неожиданностям, которые подстерегают ваш проект в течение его жизни.
В докладе будут сделаны попытки ответить на вопросы, какой тип скрывается под маской auto, почему T&& не всегда rvalue, и почему move ничего не двигает.
Обобщенное программирование в C++ или как сделать свою жизнь проще через стра...corehard_by
Обобщенное программирование - это подход к программированию, когда алгоритм пишется без указания конкретных типов данных. Используя данный подход можно значительно увеличить количество повторно используемого кода. В C++ данный подход реализуется за счет механизма шаблонов. В данном докладе рассмотрим некоторые возможности по обобщенному программированию, которые предоставляет C++. На конкретных примерах рассмотрим, как они могут упростить нам жизнь и с какими трудностями приходится сталкиваться при их использовании.
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Sergey Platonov
В последнее время в промышленной разработке ПО особую популярность обретают Domain-Specific Lanugages (DSL). Они драматически упрощают разработку и дают возможность “программировать” не только программистам, но и пользователям прикладных программ.
В своем докладе я расскажу об опыте использования DSL применительно к С++, причем упор будет сделан на производительность кода DSL, и его мгновенную “встраиваемость” в запущенную программу путем компиляции DSL-кода в нативный код с помощью инструментария LLVM.
Рассмотрены известные автору подходы к реализации как lock-free, так и fine-grained lock-based set/map: хеш-таблицы, деревья. Что из подходов STL может быть реализовано в lock-free манере, а что принципиально нет. Подводные камни lock-free и их нейтрализация.
В рамках данного выступления вас ждут:
* рассказ о полезных и интересных вещах из Boost
* новости с передовиц разработки Boost и о новинках ожидаемых в следующих версиях
* что из Boost готовится к переезду в новый стандарт С++
* как экспериментировать с Boost, имея под рукой только браузер
* что людям не нравится в Boost и как с этими людьми бороться (-:
Павел Беликов, Как избежать ошибок, используя современный C++Sergey Platonov
Одной из проблем C++ является большое количество конструкций, поведение которых не определено или просто неожиданно для программиста. С такими ошибками мы часто сталкиваемся при разработке статического анализатора кода. Но, как известно, лучше всего находить ошибки ещё на этапе компиляции. На этом докладе мы поговорим о том, какие техники из современного C++ позволяют писать не только более простой и выразительный, но и безопасный код. Вы увидите ошибки в коде различных Open Source проектов и узнаете, как можно их избежать, используя новые стандарты
Догнать и перегнать boost::lexical_castRoman Orlov
Разбор нестандартной реализации преобразования целого числа в строку без использования циклов и рекурсивных вызовов времени исполнения - только рекурсия на этапе компиляции
Фитнес для вашего кода: как держать его в формеIlia Shishkov
C++ Россия 2017
Во время моего выступления мы поговорим о принципе "Minimize coupling, maximize cohesion". Обсудим, что это такое и что значат эти непонятные слова. Кроме того на приближенном к реальности примере мы рассмотрим, как, применяя указанный принцип, можно держать ваш код в форме, чтобы он был готов ко всем неожиданностям, которые подстерегают ваш проект в течение его жизни.
В докладе будут сделаны попытки ответить на вопросы, какой тип скрывается под маской auto, почему T&& не всегда rvalue, и почему move ничего не двигает.
Обобщенное программирование в C++ или как сделать свою жизнь проще через стра...corehard_by
Обобщенное программирование - это подход к программированию, когда алгоритм пишется без указания конкретных типов данных. Используя данный подход можно значительно увеличить количество повторно используемого кода. В C++ данный подход реализуется за счет механизма шаблонов. В данном докладе рассмотрим некоторые возможности по обобщенному программированию, которые предоставляет C++. На конкретных примерах рассмотрим, как они могут упростить нам жизнь и с какими трудностями приходится сталкиваться при их использовании.
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Sergey Platonov
В последнее время в промышленной разработке ПО особую популярность обретают Domain-Specific Lanugages (DSL). Они драматически упрощают разработку и дают возможность “программировать” не только программистам, но и пользователям прикладных программ.
В своем докладе я расскажу об опыте использования DSL применительно к С++, причем упор будет сделан на производительность кода DSL, и его мгновенную “встраиваемость” в запущенную программу путем компиляции DSL-кода в нативный код с помощью инструментария LLVM.
Рассмотрены известные автору подходы к реализации как lock-free, так и fine-grained lock-based set/map: хеш-таблицы, деревья. Что из подходов STL может быть реализовано в lock-free манере, а что принципиально нет. Подводные камни lock-free и их нейтрализация.
В рамках данного выступления вас ждут:
* рассказ о полезных и интересных вещах из Boost
* новости с передовиц разработки Boost и о новинках ожидаемых в следующих версиях
* что из Boost готовится к переезду в новый стандарт С++
* как экспериментировать с Boost, имея под рукой только браузер
* что людям не нравится в Boost и как с этими людьми бороться (-:
Павел Беликов, Как избежать ошибок, используя современный C++Sergey Platonov
Одной из проблем C++ является большое количество конструкций, поведение которых не определено или просто неожиданно для программиста. С такими ошибками мы часто сталкиваемся при разработке статического анализатора кода. Но, как известно, лучше всего находить ошибки ещё на этапе компиляции. На этом докладе мы поговорим о том, какие техники из современного C++ позволяют писать не только более простой и выразительный, но и безопасный код. Вы увидите ошибки в коде различных Open Source проектов и узнаете, как можно их избежать, используя новые стандарты
Евгений Зуев, С++ в России: Стандарт языка и его реализацияPlatonov Sergey
Доклад посвящён различным аспектам компилятора С++, созданного с участием автора. В выступлении рассказывается о продвинутой архитектуре компилятора, основных проектных решениях, а также обсуждаются особенности входного языка, повлиявшие на реализацию компилятора.
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведенияPlatonov Sergey
В этом докладе Дмитрий кратко рассказывает о таком звере, как LLVM, о котором много кто слышал, но немногие щупали.
Что такое компилятор на самом деле? Как происходит компиляция программы, как работают оптимизации и, наконец, откуда берется неопределенное поведение в детерменированных программах на C++?
Доклад вводит в рассмотрение универсальный адаптер, позволяющий обернуть любой класс с целью добавления новых свойств, отсутствующих в оригинальном классе. Получаемые классы могут иметь в точности такой же интерфейс, как и первоначальные, что позволяет прозрачно заменять их и оборачивать любое количество раз.
Это позволяет добавлять необходимые свойства объектам, не переписывая его с нуля. Предложенная обобщенная концепция будет последовательно введена и проиллюстрирована простыми, но интересными примерами.
ЛЕКЦИЯ 4. Шаблоны многопоточного программирования
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
ЛЕКЦИЯ 8. Многопоточное программирование без использования блокировок. Модель потребитель-производитель. Потокобезопасный стек. Проблема ABA. Указатели опасности.
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
ЛЕКЦИЯ 5. Шаблоны многопоточного программирования
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»Platonov Sergey
За время работы над проектом был разработан удобный фреймворк для написания асинхронного кода. В докладе будет рассмотрено то, как он устроен и как со временем эволюционировал. Разберемся, как с помощью наших примитивов решать проблемы, часто встречающиеся в асинхронном программирование; будут примеры удачного и неудачного использования. Отдельно остановимся на сравнении получившихся средств с тем, что было добавлено в С++11.
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...Alexey Paznikov
ЛЕКЦИЯ 5. Многопоточное программирование в языке С++. Работа с потоками. Защита данных. Синхронизация. Будущие результаты
Курс "Параллельные вычислительные технологии" (ПВТ), осень 2014
Сибирский государственный университет телекоммуникаций и информатики
преподаватель:
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...Alexey Paznikov
ЛЕКЦИЯ 6. Атомарные операции. Внеочередное выполнение инструкций. Барьеры памяти. Семантика захвата-освобождения. Модель памяти C++
Курс "Параллельные вычислительные технологии" (ПВТ), осень 2014
Сибирский государственный университет телекоммуникаций и информатики
преподаватель:
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
Григорий Демченко, Асинхронность и неблокирующая синхронизацияSergey Platonov
Практика показывает, что использование подхода, основанного на колбеках для асинхронного программирования обычно не является удобным и подвержено различным ошибкам. Для упрощения написания и поддержки сложных асинхронных программ можно использовать несколько иной подход: использовать сопрограммы для переключения контекста на время ожидания события. Такой подход позволяет реализовать интересные неблокирующие примитивы, включая неблокирующее сетевое взаимодействие, неблокирующие мьютексы, а также удобное переключение между различными пулами потоков для разнесения выполнения задач, которые требуют различные ресурсы.
ЛЕКЦИЯ 3. Реентерабельность. Сигналы. Локальные данные потоков. Принудительное завершение потоков
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Андрей Карпов
Вы узнаете, что такое статический анализ кода и историю его развития. Узнаете, как эффективно применять инструменты статического анализа в своей работе, увидите практические примеры использования этой методологии. Доклад ориентирован на программистов, использующих языки Си/Си++, но будет полезен всем
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...Alexey Paznikov
ЛЕКЦИЯ 6. Разработка параллельных структур данных на основе блокировок
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Объектно-Ориентированное Программирование на C++, Лекции 3 и 4 Dima Dzuba
Описываются возможности C++ по работе с наследованием (virtual, override, final). Описываются механизмы работы с константными переменными и методами (const, mutable, constexpr). Описываются возможности по перегрузке операторов (operator).
Дмитрий Прокопцев, Яндекс
Речь пойдёт о, наверное, одном из самых важных и в то же время сложных нововведений в С++11 — R-ссылках (rvalue references). Мы рассмотрим базовые правила работы с такими ссылками и связанные с ними новые концепции языка: перемещение классов, универсальные ссылки и перенаправление вызовов.
Евгений Зуев, С++ в России: Стандарт языка и его реализацияPlatonov Sergey
Доклад посвящён различным аспектам компилятора С++, созданного с участием автора. В выступлении рассказывается о продвинутой архитектуре компилятора, основных проектных решениях, а также обсуждаются особенности входного языка, повлиявшие на реализацию компилятора.
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведенияPlatonov Sergey
В этом докладе Дмитрий кратко рассказывает о таком звере, как LLVM, о котором много кто слышал, но немногие щупали.
Что такое компилятор на самом деле? Как происходит компиляция программы, как работают оптимизации и, наконец, откуда берется неопределенное поведение в детерменированных программах на C++?
Доклад вводит в рассмотрение универсальный адаптер, позволяющий обернуть любой класс с целью добавления новых свойств, отсутствующих в оригинальном классе. Получаемые классы могут иметь в точности такой же интерфейс, как и первоначальные, что позволяет прозрачно заменять их и оборачивать любое количество раз.
Это позволяет добавлять необходимые свойства объектам, не переписывая его с нуля. Предложенная обобщенная концепция будет последовательно введена и проиллюстрирована простыми, но интересными примерами.
ЛЕКЦИЯ 4. Шаблоны многопоточного программирования
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
ЛЕКЦИЯ 8. Многопоточное программирование без использования блокировок. Модель потребитель-производитель. Потокобезопасный стек. Проблема ABA. Указатели опасности.
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
ЛЕКЦИЯ 5. Шаблоны многопоточного программирования
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»Platonov Sergey
За время работы над проектом был разработан удобный фреймворк для написания асинхронного кода. В докладе будет рассмотрено то, как он устроен и как со временем эволюционировал. Разберемся, как с помощью наших примитивов решать проблемы, часто встречающиеся в асинхронном программирование; будут примеры удачного и неудачного использования. Отдельно остановимся на сравнении получившихся средств с тем, что было добавлено в С++11.
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...Alexey Paznikov
ЛЕКЦИЯ 5. Многопоточное программирование в языке С++. Работа с потоками. Защита данных. Синхронизация. Будущие результаты
Курс "Параллельные вычислительные технологии" (ПВТ), осень 2014
Сибирский государственный университет телекоммуникаций и информатики
преподаватель:
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...Alexey Paznikov
ЛЕКЦИЯ 6. Атомарные операции. Внеочередное выполнение инструкций. Барьеры памяти. Семантика захвата-освобождения. Модель памяти C++
Курс "Параллельные вычислительные технологии" (ПВТ), осень 2014
Сибирский государственный университет телекоммуникаций и информатики
преподаватель:
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
Григорий Демченко, Асинхронность и неблокирующая синхронизацияSergey Platonov
Практика показывает, что использование подхода, основанного на колбеках для асинхронного программирования обычно не является удобным и подвержено различным ошибкам. Для упрощения написания и поддержки сложных асинхронных программ можно использовать несколько иной подход: использовать сопрограммы для переключения контекста на время ожидания события. Такой подход позволяет реализовать интересные неблокирующие примитивы, включая неблокирующее сетевое взаимодействие, неблокирующие мьютексы, а также удобное переключение между различными пулами потоков для разнесения выполнения задач, которые требуют различные ресурсы.
ЛЕКЦИЯ 3. Реентерабельность. Сигналы. Локальные данные потоков. Принудительное завершение потоков
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Андрей Карпов
Вы узнаете, что такое статический анализ кода и историю его развития. Узнаете, как эффективно применять инструменты статического анализа в своей работе, увидите практические примеры использования этой методологии. Доклад ориентирован на программистов, использующих языки Си/Си++, но будет полезен всем
ПВТ - весна 2015 - Лекция 6. Разработка параллельных структур данных на основ...Alexey Paznikov
ЛЕКЦИЯ 6. Разработка параллельных структур данных на основе блокировок
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Объектно-Ориентированное Программирование на C++, Лекции 3 и 4 Dima Dzuba
Описываются возможности C++ по работе с наследованием (virtual, override, final). Описываются механизмы работы с константными переменными и методами (const, mutable, constexpr). Описываются возможности по перегрузке операторов (operator).
Дмитрий Прокопцев, Яндекс
Речь пойдёт о, наверное, одном из самых важных и в то же время сложных нововведений в С++11 — R-ссылках (rvalue references). Мы рассмотрим базовые правила работы с такими ссылками и связанные с ними новые концепции языка: перемещение классов, универсальные ссылки и перенаправление вызовов.
Generics were added to the Java language more than 10 year ago. But do you really understand them?
We’ll discuss:
What is heap pollution?
How does the compiler translate generics?
Why it’s not allowed to create parametrized array (List<string>[])
What are bridge methods, can we reach them?
Type erasure rules
Difference between List, List<object>, List<?>
Why it’s not allowed to add Integer to List<?>
Why it’s not allowed to parameterize exception classes?
What’s wrong with Collections.max signature: <t><?>> T max(Collection<?> coll);
Code that should be compiled, but can’t be compiled and vice versa
How to write good API using generics and wildcards
And other generic puzzlers
ЛЕКЦИЯ 1. Актуальность параллельных вычислений. Анализ параллельных алгоритмов. Многоядерные вычислительные систем с общей памятью
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Опыт разработки статического анализатора кодаAndrey Karpov
Один из основателей проекта PVS-Studio расскажет об опыте разработки статического анализатора кода C++. У инструментов статического анализа кода существует "проблема айсберга". От пользователей скрыты сложные механизмы анализа кода, и иногда им кажется, что статические анализаторы – это просто какие-то утилиты, ищущие опечатки с помощью регулярных выражений. Автор доклада постарается в общих чертах описать, как всё обстоит на самом деле. Он покажет на примерах, почему нормальный анализ с помощью регулярных выражений нереализуем, что такое Data Flow анализ, а также расскажет о других технологиях, применяемых при анализе кода. Вкратце будет затронут вопрос использования нейронных сетей, обсуждение которых сейчас является очень модной темой, и рассказано, почему с точки зрения анализа кода отношение к этому направлению является очень скептическим.
Rust: абстракции и безопасность, совершенно бесплатноOpen-IT
Владимир Матвеев: "Rust: абстракции и безопасность, совершенно бесплатно" (Обзор языка Rust: для чего он предназначен, его ключевые особенности, инфраструктура)
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...Yandex
Основываясь на опыте разработки Крипты, Дмитрий рассмотрит средства реализации статического и динамического полиморфизма в C++, а также некоторые их паттерны и антипаттерны.
Статический и динамический полиморфизм в C++, Дмитрий ЛевановYandex
На примере некоторых архитектурных решений Крипты Дмитрий расскажет о способах реализации полиморфного поведения в программах на C++, о преимуществах и недостатках этих способов, а также о новых возможностях C++11.
Статический анализ: вокруг Java за 60 минутAndrey Karpov
Статический анализ всё больше воспринимается как неотъемлемая часть процесса разработки качественного программного обеспечения. Разумеется, у этой технологии уже есть свои сторонники и противники, но, несмотря на это, тема статического анализа всё более актуальна и требует детального рассмотрения. Рассмотрим, что такое статический анализ, как он применяется и как влияет на качество и надёжность кода. Поговорим о важности раннего обнаружения ошибок и дефектов уязвимости. Рассмотрим существующие инструменты для Java, такие как Sonar Java, FindBugs и анализатор встроенном в среду разработки IntelliJ IDEA. Расскажем историю, почему несмотря на уже существующие инструменты, мы решили разработать PVS-Studio для Java, как мы это делали и что в итоге получилось. В конце затронем вопрос интеграции статических анализаторов кода в большие старые проекты. Другими словами, как увидеть 100500 срабатываний и не упасть духом.
Оптимизация трассирования с использованием Expression templatesPlatonov Sergey
В докладе будет рассказано о тех фундаментальных причинах, приводящих к неоптимальному коду в продукте, будет предложен подход, лишённый найденных недостатков.
Докладываемый подход опирается на технологию Expression Templates, которая позволяет уменьшить количество действий и объём ресурсов, которые требуются для выполнения неких промежуточных действий в процессе формирования каждой записи в журнал. Эта технология используется для уменьшения количества промежуточных операций при вычислении сложных математических выражений. Новизна докладываемого подхода в том, что тот же самый принцип, на котором основана технология Expression Templates можно применить для того, чтобы целенаправленно исключить те промежуточные действия, которые в конечном итоге приводят к неоптимальному коду.
Завершается доклад обсуждением полученного эффекта, путей возможного дальнейшего развития и возможностей применения этой же технологии в других задачах.
Similar to Метапрограммирование в C++11/14 и C++17. Новые инструменты - новые проблемы. (20)
3. 3/38
Метапрограммирование
Что это и зачем оно нужно?
Что такое метапрограммирование?
Это реализация алгоритмов, входными/выходными данными которых
являются другие программные сущности (классы, функции, …).
4. 3/38
Метапрограммирование
Что это и зачем оно нужно?
Что такое метапрограммирование?
Это реализация алгоритмов, входными/выходными данными которых
являются другие программные сущности (классы, функции, …).
Метапрограммирование или generic programming?
Generic programming – это способ обобщения реализации (или реализаций)
для разнородных типов данных.
Метапрограммирование – это программирование, подразумевает
описание процесса вычислений.
5. 3/38
Метапрограммирование
Что это и зачем оно нужно?
Что такое метапрограммирование?
Это реализация алгоритмов, входными/выходными данными которых
являются другие программные сущности (классы, функции, …).
Метапрограммирование или generic programming?
Generic programming – это способ обобщения реализации (или реализаций)
для разнородных типов данных.
Метапрограммирование – это программирование, подразумевает
описание процесса вычислений.
Зачем нужно метапрограммирование?
Ускорение выполнения программы, перенос части вычислений на этап
компиляции (zero-overhead abstrac ons).
7. 5/38
Constexpr if statement
Когда его ещё не придумали
template<class T>
std::enable_if_t<(std::is_floating_point_v<T> || sizeof(T) > 4), T>
div10(T x) {
return x / 10;
}
template<class T>
std::enable_if_t<(std::is_unsigned_v<T> && sizeof(T) <= 4), T>
div10(T x) {
return (0xcccccccdULL * x) >> 0x23;
}
template<class T>
std::enable_if_t<(std::is_signed_v<T> && sizeof(T) <= 4), T>
div10(T x) {
auto const t = 0x66666667LL * x;
using U = std::make_unsigned_t<decltype(t)>;
return (t >> 0x22) + ((U)t >> 0x3f);
}
8. 6/38
Constexpr if statement
Synopsis
if constexpr ([init-statement] condition)
statement
[else
statement]
template<class T>
T div10(T x) {
if constexpr (std::is_floating_point_v<T> || sizeof(T) > 4) //[+]
return x / 10;
else if constexpr (std::is_unsigned_v<T>) //[+]
return (0xcccccccdULL * x) >> 0x23;
else {
auto const t = 0x66666667LL * x;
using U = std::make_unsigned_t<decltype(t)>;
return (t >> 0x22) + ((U)t >> 0x3f);
}
}
9. 6/38
Constexpr if statement
Synopsis
if constexpr ([init-statement] condition)
statement
[else
statement]
template<class T>
T div10(T x) {
if constexpr (std::is_floating_point_v<T> || sizeof(T) > 4) //[+]
return x / 10;
else if (std::is_unsigned_v<T>) //[-]
return (0xcccccccdULL * x) >> 0x23;
else {
auto const t = 0x66666667LL * x;
using U = std::make_unsigned_t<decltype(t)>;
return (t >> 0x22) + ((U)t >> 0x3f);
}
}
10. 6/38
Constexpr if statement
Synopsis
if constexpr ([init-statement] condition)
statement
[else
statement]
template<class T>
T div10(T x) {
if (std::is_floating_point_v<T> || sizeof(T) > 4) //[-]
return x / 10;
else if (std::is_unsigned_v<T>) //[-]
return (0xcccccccdULL * x) >> 0x23;
else {
auto const t = 0x66666667LL * x;
using U = std::make_unsigned_t<decltype(t)>;
return (t >> 0x22) + ((U)t >> 0x3f);
}
}
11. 7/38
Constexpr if statement
AST для вещественного аргумента
-FunctionDecl used div10 ’double (double)’
|-TemplateArgument type ’double’
|-ParmVarDecl used x ’double’:’double’
‘-CompoundStmt
‘-IfStmt
|-BinaryOperator ’_Bool’ ’||’
| |-<<<...>>>
| ‘-<<<...>>>
|-ReturnStmt
| ‘-BinaryOperator ’double’ ’/’
| |-ImplicitCastExpr ’double’:’double’ <LValueToRValue>
| | ‘-DeclRefExpr lvalue ParmVar ’x’ ’double’:’double’
| ‘-ImplicitCastExpr ’double’ <IntegralToFloating>
| ‘-IntegerLiteral ’int’ 10
‘-<<<NULL>>> // <-- discarded
12. 8/38
Constexpr if statement
AST для беззнакового целочисленного аргумента
-FunctionDecl used div10 ’unsigned int (unsigned int)’
|-TemplateArgument type ’unsigned int’
|-ParmVarDecl used x ’unsigned int’:’unsigned int’
‘-CompoundStmt
‘-IfStmt
|-BinaryOperator ’_Bool’ ’||’
| |-<<<...>>>
| ‘-<<<...>>>
|-NullStmt // <-- discarded
‘-IfStmt
|-ImplicitCastExpr ’_Bool’ <LValueToRValue>
| ‘-DeclRefExpr ’const _Bool’ ’is_unsigned_v’ ’const _Bool’
|-ReturnStmt
| ‘-ImplicitCastExpr ’unsigned int’:’unsigned int’ <IntegralCast>
| ‘-BinaryOperator ’unsigned long long’ ’>>’
| |-<<<...>>>
| ‘-IntegerLiteral ’int’ 35
‘-<<<NULL>>> // <-- discarded
13. 9/38
Constexpr if statement
AST для целочисленного аргумента
-FunctionDecl used div10 ’int (int)’
|-TemplateArgument type ’int’
|-ParmVarDecl used x ’int’:’int’
‘-CompoundStmt
‘-IfStmt
|-BinaryOperator ’_Bool’ ’||’
| |-<<<...>>>
| ‘-<<<...>>>
|-NullStmt // <-- discarded
‘-IfStmt
|-ImplicitCastExpr ’_Bool’ <LValueToRValue>
| ‘-DeclRefExpr ’const _Bool’ ’is_unsigned_v’ ’const _Bool’
|-NullStmt // <-- discarded
‘-CompoundStmt
|-DeclStmt
| ‘-VarDecl used t ’const long long’:’const long long’ cinit
| ‘-<<<...>>>
|-DeclStmt
| ‘-TypeAliasDecl U ’std::make_unsigned_t<decltype(t)>’
| ‘-<<<...>>>
‘-ReturnStmt
‘-ImplicitCastExpr ’int’:’int’ <IntegralCast>
‘-<<<...>>>
14. 10/38
Constexpr if statement
и стиль кодирования
auto foo(...) {
if (condition)
return statement1;
return statement2;
}
template<typename T>
auto bar(...) {
if constexpr (condition)
return statement1;
else
return statement2;
}
15. 11/38
Constexpr if statement
Все или ничего
template<class ChT, class TrT, class T>
void print(std::basic_ostream<ChT, TrT>& os, T const& v) {
if constexpr (std::is_array_v<T>) {
os << ’[’;
auto first = std::begin(v), last = std::end(v);
if (first != last--) {
while (first != last) {
print(os, *first++);
os << ’,’;
}
print(os, *first);
}
os << ’]’;
} else {
os << v;
}
}
16. 11/38
Constexpr if statement
Все или ничего
template<class ChT, class TrT, class T>
void print(std::basic_ostream<ChT, TrT>& os, T const& v) {
if constexpr (std::is_array_v<T>) {
os << ’[’;
auto first = std::begin(v), last = std::end(v);
if (first != last--) {
while (first != last) {
print(os, *first++);
os << ’,’;
}
print(os, *first);
}
os << ’]’;
} else if constexpr (std::is_enum_v<T>) {
os << ”enum{”;
print(os, static_cast<std::underlying_type_t<T>>(v));
os << ”}”;
} else {
os << v;
}
}
17. 11/38
Constexpr if statement
Все или ничего
template<class ChT, class TrT, class T>
void print(std::basic_ostream<ChT, TrT>& os, T const& v) {
if constexpr (std::is_array_v<T>) {
os << ’[’;
auto first = std::begin(v), last = std::end(v);
if (first != last--) {
while (first != last) {
print(os, *first++);
os << ’,’;
}
print(os, *first);
}
os << ’]’;
} else if constexpr (std::is_enum_v<T>) {
os << ”enum{”;
print(os, static_cast<std::underlying_type_t<T>>(v));
os << ”}”;
} else if constexpr (...) {
...
} else {
os << v;
}
}
18. 12/38
Constexpr if statement
Проблема расширения
#include ”print.hpp”
enum class color {
red,
green,
blue
};
color c[] = {color::red, color::green, color::blue};
print(std::cout, c);
> [enum{0},enum{1},enum{2}]
19. 12/38
Constexpr if statement
Проблема расширения
#include ”print.hpp”
enum class color { ... };
template<class ChT, class TrT, class T>
void print(std::basic_ostream<ChT, TrT>& os, T v,
std::enable_if_t<std::is_enum_v<T>>* = nullptr) {
os << typeid(T).name() << ’=’;
print(os, static_cast<std::underlying_type_t<T>>(v));
}
color c[] = {color::red, color::green, color::blue};
print(std::cout, c);
> ???
20. 12/38
Constexpr if statement
Проблема расширения
#include ”print.hpp”
enum class color { ... };
template<class ChT, class TrT, class T>
void print(std::basic_ostream<ChT, TrT>& os, T v,
std::enable_if_t<std::is_enum_v<T>>* = nullptr) {
os << typeid(T).name() << ’=’;
print(os, static_cast<std::underlying_type_t<T>>(v));
}
color c[] = {color::red, color::green, color::blue};
print(std::cout, c);
> error: call to ’print’ is ambiguous
21. 12/38
Constexpr if statement
Проблема расширения
#include ”print.hpp”
enum class color { ... };
template<class ChT, class TrT, class T>
void print_enum(std::basic_ostream<ChT, TrT>& os, T v,
std::enable_if_t<std::is_enum_v<T>>* = nullptr) {
os << typeid(T).name() << ’=’;
print(os, static_cast<std::underlying_type_t<T>>(v));
}
template<class ChT, class TrT>
void print(std::basic_ostream<ChT, TrT>& os, color v) {
return print_enum(os, v);
}
color c[] = {color::red, color::green, color::blue};
print(std::cout, c);
> ???
22. 12/38
Constexpr if statement
Проблема расширения
#include ”print.hpp”
enum class color { ... };
template<class ChT, class TrT, class T>
void print_enum(std::basic_ostream<ChT, TrT>& os, T v,
std::enable_if_t<std::is_enum_v<T>>* = nullptr) {
os << typeid(T).name() << ’=’;
print(os, static_cast<std::underlying_type_t<T>>(v));
}
template<class ChT, class TrT>
void print(std::basic_ostream<ChT, TrT>& os, color v) {
return print_enum(os, v);
}
color c[] = {color::red, color::green, color::blue};
print(std::cout, c);
> [5color=0,5color=1,5color=2]
23. 12/38
Constexpr if statement
Проблема расширения
#include ”print.hpp”
enum class color { ... };
template<class ChT, class TrT>
void print(std::basic_ostream<ChT, TrT>& os, color v) {
return print_enum(os, v);
}
template<class ChT, class TrT>
void print(std::basic_ostream<ChT, TrT>& os, enum1 v) { ... }
template<class ChT, class TrT>
void print(std::basic_ostream<ChT, TrT>& os, enum2 v) { ... }
...
template<class ChT, class TrT>
void print(std::basic_ostream<ChT, TrT>& os, enumN v) { ... }
24. 13/38
Constexpr if statement
Ответ РГ21
“Как раньше могли написать плохо, так и теперь можем написать
плохо. Просто по-разному.
”Александр Фокин,
председатель РГ21 C++
26. 15/38
Метапрограммирование в С++11/14
Выделить частный случай для минимального числа параметров
template<typename T>
void print_list(T t) {
std::cout << t << std::endl;
}
Обработать ”голову” списка параметров, рекурсивно повторить для ”хвоста”
template<typename T, typename U, typename... Tail>
void print_list(T t, U u, Tail... tail) {
std::cout << t << ”, ”; // handle HEAD
return print_list(u, tail...); // handle TAIL
}
27. 16/38
Метапрограммирование в С++11/14
На примере контейнера флагов typed_flags
template<typename... Args>
class typed_flags;
Типы вместо констант и перечислений
class eats_meat;
class eats_grass;
class has_tail;
typed_flags<eats_meat, eats_grass, has_tail> wolf;
Массовая установка флагов
wolf.set<eats_grass>(false);
wolf.set<eats_meat, has_tail>();
Логические операции над множеством флагов
assert( (wolf.all<eats_meat, has_tail>()) );
assert( (wolf.any<eats_meat, has_tail, eats_grass>()) );
assert( (wolf.none<eats_grass>()) );
28. 17/38
Поиск типа в списке в C++11/14
static_assert(counter<int>::value == 0);
static_assert(counter<int, char, int, float, int>::value == 2);
29. 17/38
Поиск типа в списке в C++11/14
static_assert(counter<int>::value == 0);
static_assert(counter<int, char, int, float, int>::value == 2);
Решение на Haskell
is_same a b | a == b = 1
| otherwise = 0
counter _ [] = 0
counter x (h:t) = is_same x h + counter x t
30. 17/38
Поиск типа в списке в C++11/14
static_assert(counter<int>::value == 0);
static_assert(counter<int, char, int, float, int>::value == 2);
Решение на Haskell
is_same a b | a == b = 1
| otherwise = 0
counter _ [] = 0
counter x (h:t) = is_same x h + counter x t
Решение на C++
template<typename T, typename Head=empty, typename... Tail>
struct counter {
static constexpr size_t value = std::is_same_v<T, Head>
+ counter<T, Tail...>::value;
};
template<typename T>
struct counter<T, empty> {
static constexpr size_t value = 0;
};
31. 18/38
Поиск типа в списке в C++11/14
AST для counter<void, char, int, float>
0 -ClassTemplateDecl counter
|-TemplateTypeParmDecl referenced typename T
|-TemplateTypeParmDecl referenced typename Head
| ‘-TemplateArgument type ’struct empty’
|-TemplateTypeParmDecl referenced typename ... Tail
32. 18/38
Поиск типа в списке в C++11/14
AST для counter<void, char, int, float>
0 -ClassTemplateDecl counter
|-TemplateTypeParmDecl referenced typename T
|-TemplateTypeParmDecl referenced typename Head
| ‘-TemplateArgument type ’struct empty’
|-TemplateTypeParmDecl referenced typename ... Tail
1 |-ClassTemplateSpecializationDecl struct counter definition
| |-TemplateArgument type ’void’
| |-TemplateArgument type ’char’
| |-TemplateArgument pack
| | |-TemplateArgument type ’int’
| | ‘-TemplateArgument type ’float’
33. 18/38
Поиск типа в списке в C++11/14
AST для counter<void, char, int, float>
0 -ClassTemplateDecl counter
|-TemplateTypeParmDecl referenced typename T
|-TemplateTypeParmDecl referenced typename Head
| ‘-TemplateArgument type ’struct empty’
|-TemplateTypeParmDecl referenced typename ... Tail
1 |-ClassTemplateSpecializationDecl struct counter definition
| |-TemplateArgument type ’void’
| |-TemplateArgument type ’char’
| |-TemplateArgument pack
| | |-TemplateArgument type ’int’
| | ‘-TemplateArgument type ’float’
2 |-ClassTemplateSpecializationDecl struct counter definition
| |-TemplateArgument type ’void’
| |-TemplateArgument type ’int’
| |-TemplateArgument pack
| | ‘-TemplateArgument type ’float’
34. 18/38
Поиск типа в списке в C++11/14
AST для counter<void, char, int, float>
0 -ClassTemplateDecl counter
|-TemplateTypeParmDecl referenced typename T
|-TemplateTypeParmDecl referenced typename Head
| ‘-TemplateArgument type ’struct empty’
|-TemplateTypeParmDecl referenced typename ... Tail
1 |-ClassTemplateSpecializationDecl struct counter definition
| |-TemplateArgument type ’void’
| |-TemplateArgument type ’char’
| |-TemplateArgument pack
| | |-TemplateArgument type ’int’
| | ‘-TemplateArgument type ’float’
2 |-ClassTemplateSpecializationDecl struct counter definition
| |-TemplateArgument type ’void’
| |-TemplateArgument type ’int’
| |-TemplateArgument pack
| | ‘-TemplateArgument type ’float’
3 |-ClassTemplateSpecializationDecl struct counter definition
| |-TemplateArgument type ’void’
| |-TemplateArgument type ’float’
| |-TemplateArgument pack
35. 18/38
Поиск типа в списке в C++11/14
AST для counter<void, char, int, float>
0 -ClassTemplateDecl counter
|-TemplateTypeParmDecl referenced typename T
|-TemplateTypeParmDecl referenced typename Head
| ‘-TemplateArgument type ’struct empty’
|-TemplateTypeParmDecl referenced typename ... Tail
1 |-ClassTemplateSpecializationDecl struct counter definition
| |-TemplateArgument type ’void’
| |-TemplateArgument type ’char’
| |-TemplateArgument pack
| | |-TemplateArgument type ’int’
| | ‘-TemplateArgument type ’float’
2 |-ClassTemplateSpecializationDecl struct counter definition
| |-TemplateArgument type ’void’
| |-TemplateArgument type ’int’
| |-TemplateArgument pack
| | ‘-TemplateArgument type ’float’
3 |-ClassTemplateSpecializationDecl struct counter definition
| |-TemplateArgument type ’void’
| |-TemplateArgument type ’float’
| |-TemplateArgument pack
4 ‘-ClassTemplateSpecializationDecl struct counter definition
|-TemplateArgument type ’void’
|-TemplateArgument type ’struct empty’
|-TemplateArgument pack
36. 19/38
Проверка уникальности списка типов в C++11/14
static_assert( is_unique<>::value);
static_assert(!is_unique<int, char, int>::value);
37. 19/38
Проверка уникальности списка типов в C++11/14
static_assert( is_unique<>::value);
static_assert(!is_unique<int, char, int>::value);
Решение на Haskell
is_unique [] = True
is_unique (h:t) = counter h t == 0 && is_unique t
38. 19/38
Проверка уникальности списка типов в C++11/14
static_assert( is_unique<>::value);
static_assert(!is_unique<int, char, int>::value);
Решение на Haskell
is_unique [] = True
is_unique (h:t) = counter h t == 0 && is_unique t
Решение на C++
template<typename Head=empty, typename... Tail>
struct is_unique {
static constexpr bool value = counter<Head, Tail...>::value == 0
&& is_unique<Tail...>::value;
};
template<>
struct is_unique<empty> {
static constexpr bool value = true;
};
39. 20/38
Проверка уникальности списка типов в C++11/14
AST для is_unique<char, char, int>
0 -ClassTemplateDecl is_unique
|-TemplateTypeParmDecl referenced typename Head
| ‘-TemplateArgument type ’struct empty’
|-TemplateTypeParmDecl referenced typename ... Tail
40. 20/38
Проверка уникальности списка типов в C++11/14
AST для is_unique<char, char, int>
0 -ClassTemplateDecl is_unique
|-TemplateTypeParmDecl referenced typename Head
| ‘-TemplateArgument type ’struct empty’
|-TemplateTypeParmDecl referenced typename ... Tail
1 |-ClassTemplateSpecializationDecl struct is_unique definition
| |-TemplateArgument type ’char’
| |-TemplateArgument pack
| | |-TemplateArgument type ’char’
| | ‘-TemplateArgument type ’int’
| |-CXXRecordDecl implicit struct is_unique
| ‘-VarDecl referenced value ’const _Bool’ static inline constexpr
| ‘-BinaryOperator ’_Bool’ ’&&’
| |-BinaryOperator ’_Bool’ ’==’
| | |-ImplicitCastExpr ’size_t’:’unsigned long’ <LValueToRValue>
| | | ‘-DeclRefExpr lvalue Var 0x55aa4e871718 ’value’
41. 20/38
Проверка уникальности списка типов в C++11/14
AST для is_unique<char, char, int>
0 -ClassTemplateDecl is_unique
|-TemplateTypeParmDecl referenced typename Head
| ‘-TemplateArgument type ’struct empty’
|-TemplateTypeParmDecl referenced typename ... Tail
1 |-ClassTemplateSpecializationDecl struct is_unique definition
| |-TemplateArgument type ’char’
| |-TemplateArgument pack
| | |-TemplateArgument type ’char’
| | ‘-TemplateArgument type ’int’
| |-CXXRecordDecl implicit struct is_unique
| ‘-VarDecl referenced value ’const _Bool’ static inline constexpr
| ‘-BinaryOperator ’_Bool’ ’&&’
| |-BinaryOperator ’_Bool’ ’==’
| | |-ImplicitCastExpr ’size_t’:’unsigned long’ <LValueToRValue>
| | | ‘-DeclRefExpr lvalue Var 0x55aa4e871718 ’value’
| | | ‘-ClassTemplateSpecializationDecl struct counter definition
| | | |-TemplateArgument type ’char’
| | | |-TemplateArgument type ’char’
| | | |-TemplateArgument pack
| | | | ‘-TemplateArgument type ’int’
42. 20/38
Проверка уникальности списка типов в C++11/14
AST для is_unique<char, char, int>
0 -ClassTemplateDecl is_unique
|-TemplateTypeParmDecl referenced typename Head
| ‘-TemplateArgument type ’struct empty’
|-TemplateTypeParmDecl referenced typename ... Tail
1 |-ClassTemplateSpecializationDecl struct is_unique definition
| |-TemplateArgument type ’char’
| |-TemplateArgument pack
| | |-TemplateArgument type ’char’
| | ‘-TemplateArgument type ’int’
| |-CXXRecordDecl implicit struct is_unique
| ‘-VarDecl referenced value ’const _Bool’ static inline constexpr
| ‘-BinaryOperator ’_Bool’ ’&&’
| |-BinaryOperator ’_Bool’ ’==’
| | |-ImplicitCastExpr ’size_t’:’unsigned long’ <LValueToRValue>
| | | ‘-DeclRefExpr lvalue Var 0x55aa4e871718 ’value’
| | | ‘-ClassTemplateSpecializationDecl struct counter definition
| | | |-TemplateArgument type ’char’
| | | |-TemplateArgument type ’char’
| | | |-TemplateArgument pack
| | | | ‘-TemplateArgument type ’int’
2 |-ClassTemplateSpecializationDecl struct is_unique definition
| |-TemplateArgument type ’char’
| |-TemplateArgument pack
| | ‘-TemplateArgument type ’int’
3 ...
43. 21/38
Поиск номера типа в списке в C++11/14
static_assert(index_of<int>::value == -1);
static_assert(index_of<int, char, float, int, void>::value == 2);
44. 21/38
Поиск номера типа в списке в C++11/14
static_assert(index_of<int>::value == -1);
static_assert(index_of<int, char, float, int, void>::value == 2);
Решение на Haskell
index_of_impl _ _ [] = -1
index_of_impl x n (h:t) | x == h = n
| otherwise = index_of_impl x (n + 1) t
index_of x l = index_of_impl x 0 l
45. 21/38
Поиск номера типа в списке в C++11/14
static_assert(index_of<int>::value == -1);
static_assert(index_of<int, char, float, int, void>::value == 2);
Решение на Haskell
index_of_impl _ _ [] = -1
index_of_impl x n (h:t) | x == h = n
| otherwise = index_of_impl x (n + 1) t
index_of x l = index_of_impl x 0 l
Решение на C++
template<typename T, typename... Args>
struct index_of {
static constexpr size_t value =
index_of_impl<T, 0, Args...>::value;
};
...
46. 22/38
Поиск номера типа в списке в C++11/14
Решение на C++ (продолжение)
...
template<typename T, size_t I, typename H=empty, typename... Args>
struct index_of_impl {
static constexpr size_t value =
index_of_impl<T, I + 1, Args...>::value;
};
template<typename T, size_t I, typename... Args>
struct index_of_impl<T, I, T, Args...> {
static constexpr size_t value = I;
};
template<typename T, size_t I>
struct index_of_impl<T, I, empty> {
static constexpr size_t value = -1;
};
47. 23/38
Поиск номера типа в списке в C++11/14
AST для index_of<void, char, void, int, float>
0 -ClassTemplateDecl index_of_impl
|-TemplateTypeParmDecl referenced typename T
|-NonTypeTemplateParmDecl referenced ’size_t’:’unsigned int’ I
|-TemplateTypeParmDecl typename H
| ‘-TemplateArgument type ’struct empty’
|-TemplateTypeParmDecl referenced typename ... Args
48. 23/38
Поиск номера типа в списке в C++11/14
AST для index_of<void, char, void, int, float>
0 -ClassTemplateDecl index_of_impl
|-TemplateTypeParmDecl referenced typename T
|-NonTypeTemplateParmDecl referenced ’size_t’:’unsigned int’ I
|-TemplateTypeParmDecl typename H
| ‘-TemplateArgument type ’struct empty’
|-TemplateTypeParmDecl referenced typename ... Args
1 |-ClassTemplateSpecializationDecl struct index_of_impl definition
| |-TemplateArgument type ’void’
| |-TemplateArgument integral 0
| |-TemplateArgument type ’char’
| |-TemplateArgument pack
| | |-TemplateArgument type ’void’
| | |-TemplateArgument type ’int’
| | ‘-TemplateArgument type ’float’
| |-CXXRecordDecl implicit struct index_of_impl
49. 23/38
Поиск номера типа в списке в C++11/14
AST для index_of<void, char, void, int, float>
0 -ClassTemplateDecl index_of_impl
|-TemplateTypeParmDecl referenced typename T
|-NonTypeTemplateParmDecl referenced ’size_t’:’unsigned int’ I
|-TemplateTypeParmDecl typename H
| ‘-TemplateArgument type ’struct empty’
|-TemplateTypeParmDecl referenced typename ... Args
1 |-ClassTemplateSpecializationDecl struct index_of_impl definition
| |-TemplateArgument type ’void’
| |-TemplateArgument integral 0
| |-TemplateArgument type ’char’
| |-TemplateArgument pack
| | |-TemplateArgument type ’void’
| | |-TemplateArgument type ’int’
| | ‘-TemplateArgument type ’float’
| |-CXXRecordDecl implicit struct index_of_impl
2 ‘-ClassTemplateSpecializationDecl struct index_of_impl definition
|-TemplateArgument type ’void’
|-TemplateArgument integral 1
|-TemplateArgument type ’void’
|-TemplateArgument pack
| |-TemplateArgument type ’int’
| ‘-TemplateArgument type ’float’
|-CXXRecordDecl implicit struct index_of_impl
‘-VarDecl referenced ’const size_t’:’const unsigned int’ static constexpr
‘-SubstNonTypeTemplateParmExpr ’unsigned int’
‘-IntegerLiteral ’unsigned int’ 1
51. 25/38
Fold expressions
Folding (свертка) – функция высшего порядка, выполняющая преобразование
структуры данных при помощи заданной функции.
le fold (левоассоциативная)
foldl f i [] = i
foldl f i (h:t) = foldl f (f i h) t
foldl (+) 0 [1,2,3,4,5] = ((((0 + 1) + 2) + 3) + 4) + 5
right fold (правоассоциативная)
foldr f i [] = i
foldr f i (h:t) = f h (foldr f i t)
foldr (+) 0 [1,2,3,4,5] = 1 + (2 + (3 + (4 + (5 + 0))))
52. 25/38
Fold expressions
Folding (свертка) – функция высшего порядка, выполняющая преобразование
структуры данных при помощи заданной функции.
le fold (левоассоциативная)
foldl f i [] = i
foldl f i (h:t) = foldl f (f i h) t
foldl (+) 0 [1,2,3,4,5] = ((((0 + 1) + 2) + 3) + 4) + 5
right fold (правоассоциативная)
foldr f i [] = i
foldr f i (h:t) = f h (foldr f i t)
foldr (+) 0 [1,2,3,4,5] = 1 + (2 + (3 + (4 + (5 + 0))))
auto v = {1, 2, 3, 4, 5};
std::accumulate(std::begin(v), std::end(v), 0, std::plus<int>{});
std::accumulate(std::rbegin(v), std::rend(v), 0, std::plus<int>{});
53. 26/38
Fold expressions в C++17
unary fold
unary le fold
(. . . op pack_expression) ⇒ (((P1 op P2) op . . .) op PN)
unary right fold
(pack_expression op . . .) ⇒ (P1 op (. . . op (PN−1 op PN)))
binary fold
binary le fold
(init op . . . op pack_expression) ⇒ ((((I op P1) op P2) op . . .) op PN)
binary right fold
(pack_expression op . . . op init) ⇒ (P1 op (. . . op (PN−1 op (PN op I))))
op ∈
+ - * / % ^ & | << >>
+= -= *= /= %= ^= &= |= <<= >>= =
== != < > <= >= && || , .* ->*
54. 27/38
GSL and fold expressions (issue #749)
Рекурсия в шаблонном коде тормозит компиляцию.
template<class T>
void pbv(std::vector<T>& v) {}
template<class T, class H, class... Ts>
void pbv(std::vector<T>& v, H&& h, Ts&&... ts) {
v.push_back(h);
pbv(v, std::forward<Ts>(ts)...);
}
Рекурсии можно избежать при помощи
pack expansions
template<class T, class... Ts>
void pbv(std::vector<T>& v, Ts&&... ts) {
int _[] = {(v.push_back(ts), 0)...};
(void)_;
}
fold expressions
template<class T, class... Ts>
void pbv(std::vector<T>& v, Ts&&... ts) {
(..., v.push_back(ts));
}
55. 28/38
Поиск типа в списке в C++17
static_assert(counter<int>::value == 0);
static_assert(counter<int, char, int, float, int>::value == 2);
56. 28/38
Поиск типа в списке в C++17
static_assert(counter<int>::value == 0);
static_assert(counter<int, char, int, float, int>::value == 2);
Решение на Haskell
counter x l = foldl (r h -> r + is_same h x) 0 l
57. 28/38
Поиск типа в списке в C++17
static_assert(counter<int>::value == 0);
static_assert(counter<int, char, int, float, int>::value == 2);
Решение на Haskell
counter x l = foldl (r h -> r + is_same h x) 0 l
Решение на C++
template<typename T, typename... Args>
struct counter {
static constexpr size_t value =
(0 + ... + std::is_same_v<T, Args>);
};
58. 29/38
Поиск типа в списке в C++17
AST для counter<void, char, int, float>
0 -ClassTemplateDecl counter
|-TemplateTypeParmDecl referenced typename T
|-TemplateTypeParmDecl referenced typename ... Args
|-CXXRecordDecl struct counter definition
| |-CXXRecordDecl implicit struct counter
| ‘-VarDecl value static inline constexpr cinit
| ‘-CXXFoldExpr’<dependent type>’ // New node type
| |-IntegerLiteral ’int’ 0
| ‘-DependentScopeDeclRefExpr ’<dependent type>’ lvalue
1 ‘-ClassTemplateSpecializationDecl struct counter definition
|-TemplateArgument type ’void’
|-TemplateArgument pack
| |-TemplateArgument type ’char’
| |-TemplateArgument type ’int’
| ‘-TemplateArgument type ’float’
|-CXXRecordDecl implicit struct counter
‘-VarDecl referenced value static inline constexpr cinit
‘-ImplicitCastExpr <IntegralCast>
‘-BinaryOperator ’int’ ’+’ // f(T3) + (f(T2) + (0 + f(T1)))
|-BinaryOperator ’int’ ’+’ // f(T2) + (0 + f(T1))
| |-BinaryOperator ’int’ ’+’ // 0 + f(T1)
| | |-IntegerLiteral ’int’ 0
59. 30/38
Поиск типа в списке в C++17
Сравнительная скорость компиляции
10 20 30 40 50 60 70 80 90 100
0
0.5
1
sizeof...(Args)
t,c
C++11/14 Clang
C++11/14 GCC
C++17 Clang
C++17 GCC
61. 31/38
Проверка уникальности списка типов в C++17
static_assert( is_unique<>::value);
static_assert(!is_unique<int, char, int>::value);
Решение на Haskell
is_unique l = foldl (r h -> r && counter h l == 1) True l
62. 31/38
Проверка уникальности списка типов в C++17
static_assert( is_unique<>::value);
static_assert(!is_unique<int, char, int>::value);
Решение на Haskell
is_unique l = foldl (r h -> r && counter h l == 1) True l
Решение на C++
template<typename... Args>
struct is_unique {
static constexpr bool value =
(true && ... && (counter<Args, Args...>::value == 1));
};
63. 31/38
Проверка уникальности списка типов в C++17
static_assert( is_unique<>::value);
static_assert(!is_unique<int, char, int>::value);
Решение на Haskell
is_unique l = foldl (r h -> r && counter h l == 1) True l
Решение на C++
template<typename... Args>
struct is_unique {
static constexpr bool value =
(true && ... && (counter<Args, Args...>::value == 1));
};
Решение на C++ (unary le fold)
template<typename... Args>
struct is_unique {
static constexpr bool value =
(... && (counter<Args, Args...>::value == 1));
};
64. 32/38
Проверка уникальности списка типов в C++17
Алгоритмическая проблема
class T1; class T2; class T3; class T4; class T5;
static_assert( is_unique<T1,T2,T3,T4,T5>::value);
Явная рекурсия
1 T1 T2 T3 T4 T5 | N − 1
2 T2 T3 T4 T5 | N − 2
3 T3 T4 T5 | N − 3
4 T4 T5 | N − 4
5 T5 | N − 5
Fold expressions
1 T1 T2 T3 T4 T5 | N
2 T1 T2 T3 T4 T5 | N
3 T1 T2 T3 T4 T5 | N
4 T1 T2 T3 T4 T5 | N
5 T1 T2 T3 T4 T5 | N
66. 34/38
Поиск номера типа в списке в C++17
static_assert(index_of<int>::value == -1);
static_assert(index_of<int, char, float, int, void>::value == 2);
67. 34/38
Поиск номера типа в списке в C++17
static_assert(index_of<int>::value == -1);
static_assert(index_of<int, char, float, int, void>::value == 2);
Решение на Haskell
getn x (t,n) | x == t = n
| otherwise = -1
index_of x l = foldl (r h -> max r (getn x h)) (-1) (zip l [0..])
68. 34/38
Поиск номера типа в списке в C++17
static_assert(index_of<int>::value == -1);
static_assert(index_of<int, char, float, int, void>::value == 2);
Решение на Haskell
getn x (t,n) | x == t = n
| otherwise = -1
index_of x l = foldl (r h -> max r (getn x h)) (-1) (zip l [0..])
Решение на C++
template<typename T, typename U, typename... Args>
struct index_of_impl;
template<typename T, typename... Args>
struct index_of {
static constexpr size_t value = index_of_impl<
T, std::index_sequence_for<Args...>, Args...>::value;
};
69. 34/38
Поиск номера типа в списке в C++17
static_assert(index_of<int>::value == -1);
static_assert(index_of<int, char, float, int, void>::value == 2);
Решение на Haskell
getn x (t,n) | x == t = n
| otherwise = -1
index_of x l = foldl (r h -> max r (getn x h)) (-1) (zip l [0..])
Решение на C++
template<typename T, typename U, typename... Args>
struct index_of_impl;
template<typename T, typename... Args>
struct index_of {
static constexpr size_t value = index_of_impl<
T, std::index_sequence_for<Args...>, Args...>::value;
};
template<typename T, size_t... I, typename... Args>
struct index_of_impl<T, std::index_sequence<I...>, Args...> {
static constexpr size_t value = (size_t(-1) OP
... OP (std::is_same_v<T, Args> ? I : size_t(-1)));
};
70. 35/38
Поиск номера типа в списке в C++17
Реализация оператора свертки
template<typename T, typename Fn>
struct fold_arg {
T value;
constexpr fold_arg(T const& v): value{v} {}
constexpr explicit operator T() const { return value; }
constexpr fold_arg<T,Fn> operator <<(fold_arg<T,Fn> const& a) const {
return Fn{}(value, a.value);
}
};
71. 35/38
Поиск номера типа в списке в C++17
Реализация оператора свертки
template<typename T, typename Fn>
struct fold_arg {
T value;
constexpr fold_arg(T const& v): value{v} {}
constexpr explicit operator T() const { return value; }
constexpr fold_arg<T,Fn> operator <<(fold_arg<T,Fn> const& a) const {
return Fn{}(value, a.value);
}
};
struct min {
template<typename T>
constexpr T const& operator ()(T const& lhs, T const& rhs) const {
return lhs < rhs ? lhs : rhs;
}
};
using index = fold_arg<size_t, min>;
72. 35/38
Поиск номера типа в списке в C++17
Реализация оператора свертки
template<typename T, typename Fn>
struct fold_arg {
T value;
constexpr fold_arg(T const& v): value{v} {}
constexpr explicit operator T() const { return value; }
constexpr fold_arg<T,Fn> operator <<(fold_arg<T,Fn> const& a) const {
return Fn{}(value, a.value);
}
};
struct min {
template<typename T>
constexpr T const& operator ()(T const& lhs, T const& rhs) const {
return lhs < rhs ? lhs : rhs;
}
};
using index = fold_arg<size_t, min>;
template<typename T, size_t... I, typename... Args>
struct index_of_impl<T, std::index_sequence<I...>, Args...> {
static constexpr size_t value = static_cast<size_t>((index(-1)
<< ... << index(std::is_same_v<T, Args> ? I : -1)));
};
73. 36/38
Поиск номера типа в списке в C++17
Реализация оператора свертки (easy)
enum index: size_t {};
constexpr index operator << (index lhs, index rhs) {
return lhs < rhs ? lhs : rhs;
}
template<typename T, size_t... I, typename... Args>
struct index_of_impl<T, std::index_sequence<I...>, Args...> {
static constexpr size_t value = (index(-1) <<
... << index(std::is_same_v<T, Args> ? I : -1));
};
74. 37/38
Поиск номера типа в списке в C++17
Сравнительная скорость компиляции
0 10 20 30 40 50 60 70 80 90 100
0.2
0.4
0.6
0.8
1
1.2
1.4
Позиция искомого типа
t,c
C++11/14 Clang
C++11/14 GCC
C++17 Clang
C++17 GCC
75. 38/38
Забудьте все, чему вас учили?
Q: Как вывести последовательность аргументов с разделителем?
A1: Решите задачу рекурсивно
template<typename T>
void print_list(T t) {
std::cout << t << std::endl;
}
template<typename T, typename U, typename... Tail>
void print_list(T t, U u, Tail... tail) {
std::cout << t << ”, ”;
return print_list(u, tail...);
}
A2: Используйте fold expressions, они быстрее!
template<size_t... I, typename... Ts>
void print_list_impl(std::index_sequence<I...>, Ts... args) {
(..., (std::cout << args << (I + 1 < sizeof...(Ts) ? ”, ” : ””)));
}
template<typename... Ts>
void print_list(Ts... args) {
return print_list_impl(std::index_sequence_for<Ts...>{}, args...);
}