Полезные новации С++17. Выражения свертки (Fold expressions)

Начиная с C++11, в языке появились пакеты параметров для шаблонов с переменным количеством аргументов. Такие пакеты позволяют реализовывать функции, принимающие переменное количество параметров. Иногда эти параметры объединяются в одно выражение, чтобы на его основе можно было получить результат работы функции. Решение этой задачи значительно упростилось с выходом C++17, где появились выражения свертки.

Реализуем функцию, которая принимает переменное количество параметров арифметических типов и возвращает их сумму.

template <typename ... Ts>
auto sum(Ts ... ts)
{

   return (ts + ...);
} 
 

Следует обратить внимание на обязательность скобок в выражении (ts + ...). 
Функцию можно использовать так:

int the_sum {sum(1, 2, 3, 4, 0.5)}; // Значение: 10.5  

Общий смысл понятен. Поработаем над деталями. Первое наше упущение - отсутствие возможности работать с пустым списком параметров. Инстанцирование sum() приводит к ошибке компиляции.


error: fold of empty expansion over operator+
    return (ts + ...);
                    ^
Поправим вот так :

  return (ts + ... + 0);

Ну так получше - при пустом списке параметров и суммировании значений арифметических типов - функция возвращает 0, как и требовалось.

А как быть с не-числовыми типами, указателями и типами, определяемыми пользователем? Их обработка не входит в наши намерения. Чтобы пользователь функции не соблазнился призрачной возможностью напр. конкатенировать строки - предупредим его, добавив static_assert, с проверкой передаваемых параметров на арифметичность. Обратите внимание, что вместо '+' в свертке используем 'логическое И &&' и метафункцию is_arithmetic . 

template <typename ... Ts>
auto sum(Ts ... ts)
{
   static_assert((is_arithmetic_v<decltype(ts)> && ...),"All parameters of 'sum' function must be arithmethic");
   return (ts + ... + 0);
}

или сразу для типов

template <typename ... Ts>
auto sum(Ts ... ts)
{
   static_assert((is_arithmetic_v<Ts> && ...),"All parameters of 'sum' function must be arithmethic");
   return (ts + ... + 0);
}

Для сравнения, до появления стандарта С++17 с целью получения аналогичного результата, нам пришлось бы написать гораздо более объёмный код, который, к тому же, был бы гораздо менее понятным:

template<typename T>
T sum(T v)
{
     return v;
}

template<typename T, typename... Args>
T sum(T first, Args... args)
{
     return first + sum(args...);

}

Источники:

[1] https://en.cppreference.com/w/cpp/language/fold
[2] https://drive.google.com/open?id=1NOsO3UcXTiTrzPQkmvnvgoRwP2Z_FSwg
[3] https://tech.io/playgrounds/2205/7-features-of-c17-that-will-simplify-your-code/fold-expressions
[4] https://blog.tartanllama.xyz/exploding-tuples-fold-expressions/

Комментарии

Популярные сообщения из этого блога

Перегрузка и специализация шаблонных функций.

Ключевые слова auto и decltype – сходства, отличия и нюансы использования. Часть 3. decltype вывод типа сложного выражения.