Полезные новации С++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() приводит к ошибке компиляции.
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);
}
[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/
Реализуем функцию, которая принимает переменное количество параметров арифметических типов и возвращает их сумму.
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
Для сравнения, до появления стандарта С++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
[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/
Комментарии
Отправить комментарий