# Unpacking Tuples in C++14

Posted on February 28, 2016

C++11 introduced tuples to the C++ standard library. As the documentation says they offer a *fixed-size collection of heterogeneous values*. Unfortunately, tuples can be a little bit tricky to deal with in a generic fashion. The C++14 standard introduced a few features that greatly reduce the necessary boilerplate. In this post I will discuss how to deal with tuples with very compact code.

If you would like to follow along you can find the code examples on GitHub. Build instructions can be found in the Readme file.

## Introducing Tuples

The difficulty with tuples in C++ is that they can only be indexed at compile time. The standard library function `get`

accepts the index as a template parameter (i.e. at compile time) and returns a reference to the value at that index. The index has to be a constant expression. It cannot be dynamically generated as e.g. in a for-loop. Furthermore, since tuples can have heterogeneous values and C++ is a statically typed language there is no way to dynamically iterate over the values in a generic tuple. We wouldn’t know their types.

```
tuple<int, bool, char> t = make_tuple(1, true, 'a');
int n = get<0>(t); // ok
bool b = get<1>(t); // ok
char c = get<2>(t); // ok
for (int i = 0; i < 3; ++i) {
get<i>(t); // error: `i` is not `constexpr`
}
```

The problem can be circumvented by exploiting variadic templates, and parameter pack expansion. A feature that was also introduced in C++11. It allows to, in a way, iterate over tuple elements at compile time. First, we need to define a type that can hold a parameter pack of indices for a given tuple.

```
template <size_t... Is>
struct index_sequence;
```

Next, we can use parameter pack expansion to index into a generic tuple.

```
template <class Tuple, size_t... Is>
void function(Tuple t, index_sequence<Is...>) {
some_func( get<Is>(t)... );
}
```

Which would call `some_func`

with the tuple’s elements unpacked into its argument list.

What’s left is to construct an `index_sequence`

that contains the appropriate parameter pack of indices. The C++14 standard introduced `make_index_sequence`

for that purpose. Before that C++ programmers had to implement it themselves or pick one of the many implementations available on the Internet. E.g. this \(O(\log(N))\) implementation on Stack Overflow.

## Implementing Functions on Tuples

With all these tools available in the standard-library we can stop worrying, go ahead, and play with tuples to our heart’s content.

Suppose we wanted to implement a function that takes an arbitrary tuple and returns a new tuple that holds the first `N`

elements of the original tuple. Let’s call it `take_front`

. Since tuples have fixed size the parameter `N`

will have to be a template parameter.

```
template <class Tuple, size_t... Is>
constexpr auto take_front_impl(Tuple t,
index_sequence<Is...>) {
return make_tuple(get<Is>(t)...);
}
template <size_t N, class Tuple>
constexpr auto take_front(Tuple t) {
return take_front_impl(t, make_index_sequence<N>{});
}
```

The function `take_front_impl`

takes the input tuple and an `index_sequence`

. As before that second parameter is only there so that we can get our hands on a parameter pack of indices. We then use these indices to get the elements of the input tuple and pass them to `make_tuple`

which will construct the result. However, at that point we haven’t actually defined, yet, which elements should be put into that new tuple. This happens within `take_front`

, which constructs an index-sequence consisting of the indices `0`

to `N-1`

and passes it to `take_front_impl`

.

We can use that function like so.

```
auto t = take_front<2>(make_tuple(1, 2, 3, 4));
assert(t == make_tuple(1, 2));
```

At this point I should mention that all the code in this article is optimized for readability. In production code you would probably want to qualify members of the `std`

namespace, and use perfect forwarding. You should also be aware that the function `make_tuple`

applies non-trivial transformations to its arguments, such as converting references to values and `reference_wrapper`

to references.

With that out of the way, let’s implement another function on tuples. A very useful function that we might want to implement is `apply`

. It takes a tuple and a callable and calls the callable with the elements of the tuple as arguments. It could for example be used in the following way.

```
auto x = apply(make_tuple(1, 2), plus<>{});
assert(x == 3);
```

The implementation uses the same trick as `take_front`

before. We construct a parameter pack of integers and use a helper function to extract all the tuple elements.

```
template <class Tuple, class F, size_t... Is>
constexpr auto apply_impl(Tuple t, F f,
index_sequence<Is...>) {
return f(get<Is>(t)...);
}
template <class Tuple, class F>
constexpr auto apply(Tuple t, F f) {
return apply_impl(
t, f, make_index_sequence<tuple_size<Tuple>{}>{});
}
```

This function is actually part of the library fundamentals technical specification. Note, however, that I swapped the order of the arguments. It’s a matter of taste but I prefer callable arguments in the end of the parameter list because it allows for more readable in-line lambda definitions.

## Don’t Split Your Functions

Both of the above functions `take_front`

, and `apply`

are implemented using the same pattern. We first call `make_index_sequence`

to construct an `index_sequence`

which holds a parameter pack of indices. Then we call a helper function that accesses and unpacks that parameter pack. Unfortunately, this splits the function’s body in two pieces which makes the code harder to read. It is often said that patterns hint at a missing language feature. One could argue that the inability to create and immediately unpack parameter packs in the same place is a lacking language feature. However, here I want to discuss how to, at least, localize that pattern such that we don’t need to define helper functions outside of scope.

C++14 introduced another great feature, namely, variadic lambdas. That feature allows to define a lambda that behaves like a variadic template function. For example the following lambda returns the smallest absolute value of all given parameters.

```
auto minabs = [](auto... xs) {
return min({abs(xs)...});
};
assert(1 == minabs(-1, 2, -3));
```

This implementation uses the initializer list overload of `min`

.

Now, how could we use variadic lambdas to avoid the `*_impl`

pattern from above? A first, naive, approach follows. First, we try to separate the idea of constructing an index sequence in one place and unpacking it in another.

```
template <class F, size_t... Is>
constexpr auto index_apply_impl(F f,
index_sequence<Is...>) {
return f(Is...);
}
template <size_t N, class F>
constexpr auto index_apply(F f) {
return index_apply_impl(f, make_index_sequence<N>{});
}
```

The function `index_apply`

expects a callable and passes it to a helper function alongside a parameter pack of indices from `0`

to `N-1`

. That helper function then passes these indices as arguments to the callable. We could now try to implement `take_front`

as follows.

```
template <size_t N, class Tuple>
constexpr auto take_front(Tuple t) {
return index_apply<N>([&](auto... Is) {
return make_tuple(get<Is>(t)...);
});
}
```

This already looks very promising. We have eliminated the need for a specific helper function and can instead rely on one general helper for (hopefully) all cases. However, unfortunately, that code will not compile. The `get`

template takes the index as a template parameter. Template parameters can only be constant expressions. However, the arguments `Is...`

to the lambda are ordinary (run-time) values of type `size_t`

. Therefore, we cannot use them as template parameters.

Fortunately, there is an easy way around that problem. The standard library defines the template class `integral_constant`

which encapsulates a static constant of a specified type. Since it carries its value in a template parameter that value is a constant expression that can also be used as a parameter to other templates. Conveniently, it also defines an implicit `constexpr`

conversion operator such that we can use an `integral_constant`

object in most places where we need a constant expression of the corresponding value type. With this little helper we can implement `index_apply`

as follows.

```
template <class F, size_t... Is>
constexpr auto index_apply_impl(F f,
index_sequence<Is...>) {
return f(integral_constant<size_t, Is> {}...);
}
template <size_t N, class F>
constexpr auto index_apply(F f) {
return index_apply_impl(f, make_index_sequence<N>{});
}
```

This, finally, allows us to implement `take_front`

, and `apply`

without the need for any further helper functions.

```
template <size_t N, class Tuple>
constexpr auto take_front(Tuple t) {
return index_apply<N>([&](auto... Is) {
return make_tuple(get<Is>(t)...);
});
}
template <class Tuple, class F>
constexpr auto apply(Tuple t, F f) {
return index_apply<tuple_size<Tuple>{}>(
[&](auto... Is) { return f(get<Is>(t)...); });
}
```

Both functions call `index_apply`

, specifying how many elements we want to extract. Then they pass a variadic lambda that expects a parameter pack of indices. These indices are passed as instances of `integral_constant`

. Therefore, they can be used right away as a template argument to `get`

.

## A Few More Examples

Now that we have `index_apply`

let’s write two more functions on tuples with its help. First, let’s write a function that takes a tuple and returns a new tuple that contains the original tuple’s elements in reversed order.

```
template <class Tuple>
constexpr auto reverse(Tuple t) {
return index_apply<tuple_size<Tuple>{}>(
[&](auto... Is) {
return make_tuple(
get<tuple_size<Tuple>{} - 1 - Is>(t)...);
});
}
```

That function is nearly identical to `tuple_front`

just that this time we take the full length, and count the indices that we pass to `get`

backwards.

```
auto t = reverse(make_tuple(1, 2, 3, 4));
assert(t == make_tuple(4, 3, 2, 1));
```

Now, let’s move on to a more complex example. We will write a function that takes an arbitrary number of tuples and returns a tuple of tuples, where the first contains all the first elements of the input tuples, the second all the second elements, and so on. We’ll call this function `zip`

. We also specify that when called with zero arguments it just returns an empty tuple. If the tuples are of differing length then we will crop all inputs to match the shortest one. All in all we expect `zip`

to fulfill the following assertions.

```
assert(make_tuple() = zip());
auto t1 = zip( make_tuple(1, 2),
make_tuple(3, 4),
make_tuple(5, 6) );
assert(t1 == make_tuple( make_tuple(1, 3, 5),
make_tuple(2, 4, 6) ));
auto t2 = zip( make_tuple(1, 2, 3),
make_tuple(4) );
assert(t2 == make_tuple( make_tuple(1, 4) ));
```

It would also make sense to implement the function `transpose`

in terms of `zip`

, which takes a tuple of tuples, interprets it like a matrix, and returns a transposed tuple of tuples.

```
template <class Tuple>
constexpr auto transpose(Tuple t) {
return apply(t, [](auto... ts) { return zip(ts...); });
}
```

How could we implement `zip`

? There are a few things that we need. First, we need the length of the shortest tuple. For that purpose we can use `min`

again.

```
constexpr size_t len = min({tuple_size<Tuples>{}...});
```

Where we used the fact that `min`

is a `constexpr`

function since C++14.

Next, we need to find a way to go through every tuple and every tuple’s elements simultaneously. Unfortunately, the following, naive, implementation will not compile.

```
template <class... Tuples>
constexpr auto zip(Tuples... ts) {
constexpr size_t len = min({tuple_size<Tuples>{}...});
return index_apply<len>([&](auto... Is) {
return make_tuple(make_tuple(get<Is>(ts)...)...);
});
}
```

We somehow need to nest two parameter pack expansions. However, in the above code it is ambiguous which pack to expand first. Instead of taking a guess for us the compiler will (thankfully) simply refuse to accept this code.

We can circumvent that problem by splitting the task in two. We can think of the result as a tuple of rows where each row contains the `I`

-th elements of all input tuples. For each row the index is fixed. The outer tuple then contains all those rows. In code that reads as follows.

```
template <class... Tuples>
constexpr auto zip(Tuples... ts) {
constexpr size_t len = min({tuple_size<Tuples>{}...});
auto row =
[&](auto I) { return make_tuple(get<I>(ts)...); };
return index_apply<len>(
[&](auto... Is) { return make_tuple(row(Is)...); });
}
```

The lambda `row`

constructs a single row of `I`

-th elements of all tuples. To that end it takes one `integral_constant`

as an argument and uses it to extract one element from each tuple. Within `index_apply`

we then construct a tuple of all rows.

Finally, to handle the empty case we simply provide the following overload.

```
constexpr auto zip() { return make_tuple(); }
```

With that we have implemented `zip`

to the specification above.

## Conclusion

In this article we saw how to reduce the boilerplate when extracting elements out of generic tuples. The presented pattern allows to write the full implementation of a function that deals with generic patterns in one place without having to resort to external helper functions.

If you have any comments, thoughts, or criticism please leave a comment. In any case I hope you enjoyed the article. Thanks for reading!