Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

can't understand variadic templates in c++

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
}
like image 684
rahul tyagi Avatar asked Jun 19 '15 11:06

rahul tyagi


People also ask

What is the use of Variadic templates?

With the variadic templates feature, you can define class or function templates that have any number (including zero) of parameters. To achieve this goal, this feature introduces a kind of parameter called parameter pack to represent a list of zero or more parameters for templates.

What is a Variadic function in C?

Variadic functions are functions that can take a variable number of arguments. In C programming, a variadic function adds flexibility to the program. It takes one fixed argument and then any number of arguments can be passed.

Which of the following are valid reasons for using Variadic templates in C++?

Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration. However, variadic templates help to overcome this issue.

What means variadic?

variadic (not comparable) (computing, mathematics, linguistics) Taking a variable number of arguments; especially, taking arbitrarily many arguments.


2 Answers

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.

like image 156
WorldSEnder Avatar answered Oct 11 '22 02:10

WorldSEnder


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.

like image 22
Cory Kramer Avatar answered Oct 11 '22 03:10

Cory Kramer