Может ли кто-нибудь подробно объяснить, как работает этот рекурсивный шаблон?
Я могу попробовать.
Сначала у вас есть
template<typename... ArgTypes>
int add(ArgTypes... args);
Этообъявление функции шаблона переменной: вы объявляете, что существует add()
функция, которая получает переменное (ноль или более) число аргументов.
Внимание: вы объявляете, но не определяете функцию.
Второе: вы объявляете и , определяющие
template<typename T, typename... ArgTypes>
int add(T t, ArgTypes... args)
{
int sum = 0;
return t + add(args...);
}
a различные функции шаблона add()
, которые получают аргумент типа шаблона (t
) и шаблон списка переменных аргументов (args...
).
Строка
int sum = 0;
совершенно бесполезна, поскольку объявляет неиспользуемую переменную, но следующую строку
return t + add(args...);
выполняет работу, возвращая сумму между t
и сумму (add(args...)
) между следующими args...
.
То есть с add(args...)
рекурсивно называется int add(T t, ArgTypes... args)
, когда args...
(потому что это лучшее совпадение) не пусто и int add(ArgTypes... args)
, когда args...
- пустой список.
Но помните, что int add(ArgTypes... args)
объявлено, но не определено.
Последний пункт -
template<> int add() {
return 0;
}
, который является определением полной специализации (помните, чтовы не можете частично специализировать шаблонную функцию, но вы можете полностью специализировать ее) первой шаблонной функции в случае пустого списка.
Off Тема: вам не нужна первая шаблонная функция;Вы можете заменить его более простой функцией без шаблонов.
Вы можете переписать код следующим образом:
int add()
{ return 0; }
template <typename T, typename... ArgTypes>
int add(T t, ArgTypes... args)
{ return t + add(args...); }
и, как рекомендует Jarod42, если вы можете использовать C ++ 17, выможно полностью избежать рекурсии, используя сгибание шаблона
template <typename... ArgTypes>
int add (ArgTypes... args)
{ return (... + args); }
или, возможно, использование auto
для возврата типа.
Как добавить больше операций, таких как умножение и вычитание?
Нет представления о вычитании (как определяется вариативное вычитание?), Но для умножения вы можете использовать что-то подобное (но основной случай должен возвращать 1
, а не 0
)
int mult ()
{ return 1; }
template <typename T, typename... ArgTypes>
int mult (T t, ArgTypes... args)
{ return t * mult(args...); }
или с использованием шаблона сворачивания, из C ++ 17,
template <typename... ArgTypes>
int mult (ArgTypes... args)
{ return (... * args); }