Could anyone explain in detail how this recursive template does work?
I can try.
First you have
template<typename... ArgTypes>
int add(ArgTypes... args);
It's a variadic template function declaration: you declare that exist an add()
function that receive a variadic (zero or more) number of argumens.
Attention: you declare but not define the function.
Second: you declare and define
template<typename T, typename... ArgTypes>
int add(T t, ArgTypes... args)
{
int sum = 0;
return t + add(args...);
}
a different template function add()
that receive a template type argument (t
) and a variadic template list of arguments (args...
).
The line
int sum = 0;
is completely un-useful because declare an unused variable but the following line
return t + add(args...);
do the work returning the sum between t
and the sum (add(args...)
) between the following args...
.
So with add(args...)
is recursively called int add(T t, ArgTypes... args)
when args...
(because it's a better match) isn't empty and int add(ArgTypes... args)
when args...
is a empty list.
But remember that int add(ArgTypes... args)
is declared but not defined.
The last point is
template<> int add() {
return 0;
}
that is the definition of a full specialization (remember that you can't partial specialize a template function but you can full specialize it) of the first template function in case of empty list.
Off Topic suggestion: you don't need the first template function; you can substitute it with a simpler not-template function.
You can rewrite the code as follows
int add()
{ return 0; }
template <typename T, typename... ArgTypes>
int add(T t, ArgTypes... args)
{ return t + add(args...); }
and as suggested by Jarod42, if you can use C++17, you can completely avoid recursion using template-folding
template <typename... ArgTypes>
int add (ArgTypes... args)
{ return (... + args); }
or maybe using auto
for returning type.
How to add more operations like multiplication and subtraction?
No idea about subtraction (how is defined a variadic subtraction?) but, for multiplication you can use something similar (but the ground case must return 1
, not 0
)
int mult ()
{ return 1; }
template <typename T, typename... ArgTypes>
int mult (T t, ArgTypes... args)
{ return t * mult(args...); }
or using template folding, from C++17,
template <typename... ArgTypes>
int mult (ArgTypes... args)
{ return (... * args); }