Sometimes you have a tuple and want to pass its contents to a function as arguments. One way is to overload the function:
int average(int a, int b, int c)
{
return (a + b + c) / 3;
}
int average(std::tuple<int,int,int> x)
{
return average(std::get<0>(x), std::get<1>(x), std::get<2>(x));
}
This works for an individual function or two, but it isn't a general solution and it doesn't scale. So let's automate it.
#include <functional>
#include <tuple>
namespace detail {
template<std::size_t... Indices>
struct indices { typedef indices<Indices...,sizeof...(Indices)> next; };
// Generates the type indices<0,1,...,N-1> which is used to unpack an N-tuple.
template<std::size_t N>
struct make_indices { typedef typename make_indices<N-1>::type::next type; };
template<>
struct make_indices<0> { typedef indices<> type; };
// We use the indices to unpack the tuple.
template<class Function, class... T, std::size_t... Indices>
inline typename std::result_of<Function(T...)>::type
apply(Function f, std::tuple<T...>&& x, indices<Indices...>)
{
return f(std::forward<T>(std::get<Indices>(x))...);
}
} // namespace detail
// Apply function f to the contents of tuple x.
template<class Function, class... T>
inline typename std::result_of<Function(T...)>::type
apply(Function f, std::tuple<T...>&& x)
{
typedef typename detail::make_indices<sizeof...(T)>::type Indices;
return detail::apply(f, std::forward<std::tuple<T...>>(x), Indices());
}
Now we can call our functions this way:
int average(int a, int b, int c)
{
return (a + b + c) / 3;
}
int zero()
{
return 0;
}
int main()
{
std::cout << apply(average, std::make_tuple(1, 2, 3)) << '\n';
std::cout << apply(zero, std::make_tuple()) << '\n';
std::cout << apply([](int x, int y){ return x + y; }, std::make_tuple(2, 3)) << '\n';
}