C++11: Variadic templates (functions)

A very interesting C++0x feature are the “variadic templates” that, in short, are template classes and functions with a variable number of parameterized types. They can be useful to do several things, for example:

  • Provide type-safe replacements for functions with variable number of arguments (stdarg.h)
  • Let the user to create instances of n-tuples.
  • Create type-safe containers with elements of several types.

In this post I will take a look to the variadic template functions.

Consider I want to write a show() function that receives any number of parameters and shows them separated by a whitespace.

So, the following calls would be valid:

show(1, 2, 3); //that would output 1 2 3
show("Today is ", dayOfTheWeek); //that would output "Today is Tuesday"
show(p1, p2, p3, p4, p5);

In plain old C, you could implement something similar using the variable argument functions and the stdarg.h library; but you have two problems with that approach:

  • You have to provide the function with the number of arguments that the function will have [implicit or explicitly]
  • Your function will not be type-safe
void show(int n, ...)
{
    va_list x;
    va_start(x, n);
    for (int i = 0; i < n; i++)
    {
      //retrieve the parameter with va_arg and show it. You don't have type info here.
    }

    va_end(x);
}

In C++ you would have two partial solutions for this problem; one, would be creating several overloaded functions, similar to this implementation:

template <typename T1>
void show(const T1& t1)
{
  cout << t1 << endl;
}

template <typename T1, typename T2>
void show(const T1& t1, const T2& t2)
{
  cout << t1 << t2 << endl;

template <typename T1, typename T2, typename T3>
void show(const T1& t1, const T2& t2, const T3& t3)
{
  cout << t1 << t2 << t3 << endl;
}

and so on….

The other one would be having a base class (similar to Java object model) and have a method similar to this one:

void show(Object* o1, Object* o2 = NULL, Object* o3 = NULL, Object* o4 = NULL, Object* o5 = NULL, Object* o6 = NULL)
{
  cout << o1->toString();
  if (o2)
    cout << o2->toString();
  if (o3)
    cout << o3->toString();
  if (o4)
    cout << o4->toString();
  if (o5)
    cout << o5->toString();
  if (o6)
    cout << o6->toString();

  cout << endl;
}

Though they would work, they both have their weaknesses; both will support just a fix number of arguments, in the first implementation you must to provide N overloads to support N parameters and in the second implementation you must to provide a class hierarchy to work properly.

So, the variadic templates perform a type expansion similar to the template-based implementation, but that is done by the compiler instead of us.

What is interesting in such expansion, is that it is performed recursively.

Look at this code that implements the show function with variadic templates:

template <typename T>
void show(const T& value)
{
	cout << value << endl;
}

template <typename U, typename... T>
void show(const U& head, const T&... tail)
{
	cout << head;
	show(tail...);
}

The first overload will be the boundary case, when just a parameter is passed to the show method or when all the other overloads have been already expanded.

The second overload is very interesting because we declare a function that takes two types: U, and T. U represents a type, but T represents a list of types (look the … syntax). The argument list of the function is also interesting; head will be a const reference to a value of type U, and ...tail will represent to a set of const references of several types.

So, look into the implementation. We take the head and show it using cout and later on we will invoke show passing it the list of parameters. In this point, if the list of parameters represents to more than one type, the compiler will create a new overload for this method, and if the list of parameters represents to only one type, the compiler will invoke to the first overload already defined.

Amazing, isn’t it?

Advertisements

One thought on “C++11: Variadic templates (functions)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s