Skip to content

Variadic templates, part 1

November 23, 2011

C++11 has added the ability to create templates that have an arbitrary number of arguments, these are called variadic templates. Variadic templates can be used with both classes and functions, for part 1 I will just talk about classes.

The syntax for a class templated with a variadic argument is the same as for standard templates, except that the last argument is written with ... after the keyword typename.

For example, the stl tuple class is defined as:

template <typename... Args>
class tuple;

Tuple is like a pair, except that an instance of a tuple will hold as many objects as you ask for, instead of just two.

A variadic argument can be defined as either typenames or non-type parameters. The variadic argument is referred to as a template pack, and can have zero or more actual parameters in it.

There are several ways to use a template pack. The first is to simply expand it. To expand a template pack, type the name of the template pack parameter followed by ..., note that all uses of a template pack parameter must be expanded. For example, the following class, which when instantiated, contains an array of size_t filled with elements given in the variadic template list.

template <size_t... Entries>
struct StaticArray
{
  enum {N = sizeof...(Entries)};
  size_t array[N] = {Entries...};
};

For example, an object of type StaticArray<1,2,3,4> would have a member array of size 4 with elements 1, 2, 3, 4.

Often, you will want to write code that makes decisions looking at each parameter one at a time. The code below has a class find_biggest which has a typedef field type which is the type of the biggest class in the parameter pack, the first such one if there are multiple the same size.

template <typename... Args>
struct find_biggest;

//the biggest of one thing is that one thing
template <typename First>
struct find_biggest<First>
{
  typedef First type;
};

//the biggest of everything in Args and First
template <typename First, typename... Args>
struct find_biggest<First, Args...>
{
  typedef typename find_biggest<Args...>::type next;
  typedef typename std::conditional
  <
    sizeof(First) >= sizeof(next),
    First,
    next
  >::type type;
};

Notice that the second specialisation of find_biggest creates another instantiation of find_biggest but with the First parameter dropped. Eventually this instantiates the first specialisation with only one parameter. The biggest of one thing is obviously itself.

The technique that I used above is standard. You will often want to write code that pulls out one or several arguments from a parameter pack and then does something else with whatever is left.

The full example can be obtained from http://jarrydb.web.cse.unsw.edu.au/thenewcpp/variadic_biggest.hpp.

About these ads
4 Comments
  1. I noticed that when you write the following:


    template
    struct StaticArray{
    size_t array[] = { Args... }
    };

    trying to compile via clang 3.4 results is
    it results in a compiler error:
    “array bound cannot be deduced from an in-class initializer.”

    In gcc-4.9 I believe I got the same error
    “too many initializers for ‘size_t [0] ..’

    One way to fix it (for me) was to define the size explicitly as follow:


    template
    struct StaticArray{
    enum { N = sizeof...(Args) };
    size_t array[N] = { Args... }
    };

Trackbacks & Pingbacks

  1. Variadic templates, part 2 « The New C++
  2. Variadic templates, part 3 (or how I wrote a variant class) « The New C++

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

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: