The problem is: we have a std::tuple<T1, T2, ...>
and we have some function f
that we can to call on each element, where f
returns an int
, and we want to store those results in an array.
Let's start with a concrete case:
template <typename T> int f(T ) { return sizeof(T); }
std::tuple<int, char, double> tup{42, 'x', 3.14};
std::array<int, 3> arr{ f(std::get<0>(tup)),
f(std::get<1>(tup)),
f(std::get<2>(tup)) );
Except writing out all those get
s is inconvenient and redundant at best, error-prone at worst.
First we need to include the utility header for std::index_sequence
and std::make_index_sequence
:
#include <utility>
Now, let's say we had a type index_sequence<0, 1, 2>
. We could use that to collapse that array initialization into a variadic pack expansion:
template <typename Tuple, size_t... Indices>
std::array<int, sizeof...(Indices)>
call_f_detail(Tuple& tuple, std::index_sequence<Indices...> ) {
return { f(std::get<Indices>(tuple))... };
}
That's because within the function, f(std::get<Indices>(tuple))...
gets expanded to f(std::get<0>(tuple)), f(std::get<1>(tuple)), f(std::get<2>(tuple))
. Which is exactly what we want.
The last detail of the problem is just generating that particular index sequence. C++14 actually gives us such a utility named make_index_sequence
template <typename Tuple>
std::array<int, std::tuple_size<Tuple>::value>
call_f(Tuple& tuple) {
return call_f_detail(tuple,
// make the sequence type sequence<0, 1, 2, ..., N-1>
std::make_index_sequence<std::tuple_size<Tuple>::value>{}
);
}
whereas the article you linked simply explains how one might implement such a metafunction.
Bare
is probably something like, from Luc Danton's answer:
template<typename T>
using Bare = typename std::remove_cv<typename std::remove_reference<T>::type>::type;