I was reading about variadic templates and I came across this example. The book mentions that to end the recursion process, the function print()
is used. I really can't understand its use. Why does the author use this empty print()
function?
void print () // can't get why this function is used
{
}
template <typename T, typename... Types>
void print (const T& firstArg, const Types&... args)
{
std::cout << firstArg << std::endl; // print first argument
print(args...); // call print() for remaining arguments
}
A variadic expression can capture 0 arguments or more.
Take for example the call print(1)
. Then T
captures int
and Types = {}
- it captures no arguments. Thus the call print(args...);
expands to print();
, which is why you need a base case.
You don't need the recursion at all. I always use the following debuglog
function in my code (modified for your needs):
template<typename F, typename ... Args>
void
print(const F& first, const Args&... args) // At least one argument
{
std::cout << first << std::endl;
int sink[] =
{ 0, ((void)(std::cout << args << std::endl), 0)... };
(void) sink;
}
Because this variadic function takes at least one argument, you are free to use print(void)
for whatever you like now.
It is recursive because the variadic part of the template is reduced each call, for example a call would recursively look like this
print(1, 2, 3, 4, 5) // firstArg == 1
// ...args == 2,3,4,5
print(2, 3, 4, 5) // firstArg == 2
// ...args == 3,4,5
print(3, 4, 5) // firstArg == 3
// ...args == 4,5
print(4, 5) // firstArg == 4
// ...args == 5
print(5) // firstArg == 5
// ...args == {}
print()
The print()
is necessary as a base case for when the variadic list is empty.
Consider a call to the template function with a single argument.
print(1);
firstArg
would bind to the 1
(T = int
), and Types...
would bind to nothing. A variadic argument pack is zero or more arguments.
Thus, in this call:
print(args...);
args...
is an empty parameter pack. So it expands into:
print();
Since your function template matches any call to print with one or more arguments, you need a separate function to handle zero arguments. Which in this case is the trivial function:
void print () { }
Assume the following code:
int a, b, c;
print(a, b, c);
The compiler will implicitly create the following code:
print(const int& firstArg)
{
std::cout << firstArg << std::endl; // print first argument
print(); // call print() for remaining arguments
}
print(const int& firstArg, const int& arg2)
{
std::cout << firstArg << std::endl; // print first argument
print(arg2); // call print() for remaining arguments
}
print(const int& firstArg, const int& arg2, const int& arg3)
{
std::cout << firstArg << std::endl; // print first argument
print(arg2, arg3); // call print() for remaining arguments
}
as you can see in the version with only one argument, the compiler will call a "print" method with no arguments. Since the variadic print function ALWAYS requires at least one parameter this will not match...
来源:https://stackoverflow.com/questions/30937379/cant-understand-variadic-templates-in-c