Skip to content

Variadic templates, part 2

November 29, 2011

In my last post, Variadic templates, part 1, I discussed variadic templates only as far as parameters to a class, however, they can also be used for function parameters.

Variadic template parameters to functions have almost the same syntax as for classes, the only difference being that variadic function arguments can also be passed. For example, in the following code, the function output prints all its arguments separated by spaces.

#include <iostream>

template <typename T>
void output(T&& t)
{
  std::cout << t;
}

template <typename First, typename... Args>
void output(First&& f, Args&&... args)
{
  std::cout << f << " ";
  output(std::forward<Args>(args)...);
}

Note that each time we call output, it is with one less argument. I’ve also used std::forward here, I will explain it in much more detail in a later post. For now it’s enough to know that it passes the type of its argument exactly as called. So if the argument was an r-value reference, it stays as an r-value reference when passed to the callee.

The next thing to note is that the ... is placed outside of the call to std::forward. This has the effect of expanding args but calling std::forward separately for every single argument in the template parameter pack.

The way that template a parameter pack is unpacked as above is quite important. The following code demonstrates another use of this

template <size_t... Args>
struct call_n_args
{
  template <typename F, typename Container>
  auto
  operator()(F f, const Container& c)
    -> decltype(f(c.at(Args)...))
  {
    return f(c.at(Args)...);
  }
};

template <typename F>
auto
foo(F f, const std::vector<int>& v)
  -> decltype(call_n_args<2,1,5,4>()(f, v))
{
  return call_n_args<2,1,5,4>()(f, v);
}

The template call_n_args calls the function f with the requested elements from the given container. Note that in the line return f(c.at(Args)...), Args is expanded outside of the call to c.at. So when called from the function foo, rather than this being c.at(2,1,5,4), it actually results in f(c.at(2), c.at(1), c.at(5), c.at(4)).

The full code can be found at http://jarrydb.web.cse.unsw.edu.au/thenewcpp/variadic_expand.cpp

Advertisements
7 Comments
  1. In the first example, line 9 should be:

    template

  2. Gah, the angle brackets got eaten… let me try again with HTML escaping (for want of a “preview” button):

    template <typename First, typename… Args>

Trackbacks & Pingbacks

  1. R-value references and move semantics « 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

%d bloggers like this: