So as it turns out, the C++14 standard makes expanding a tuple, pair, or array, in a function call, very simple.
template <typename Func, typename TupleType,
std::size_t... Is>
decltype(auto) call_with_tuple_impl(
Func&& f, TupleType&& tup,
std::index_sequence<Is...>) {
return f(std::get<Is>(tup)...);
}
template <typename Func, typename TupleType>
decltype(auto) call_with_tuple(
Func&& f, TupleType&& tup) {
constexpr auto TUP_SIZE = std::tuple_size<
std::decay_t<TupleType>>::value;
return call_with_tuple_impl(
std::forward<Func>(f),
std::forward<TupleType>(tup),
std::make_index_sequence<TUP_SIZE>{});
}
Much less painful than its C++11 equivalent. std::integer_sequence is responsible for most of the ease. Combined with auto functions, which deduce their own return type, that is.
call_with_tuple first determines the tuple_size of the tuple-like object passed in. std::make_index_sequence will result in an index sequence of 0, 1, ..., TUP_SIZE. The last argument of call_with_tuple_impl is used to deduce the Is... pack. finally the mf(std::get<Is>(tup)...) is the equivalent of mf(std::get<0>(tup), std::get<1>(tup), ..., std::get<TUP_SIZE-1>(tup)).
The std::decay_t is necessary because TupType is a universal reference.
I’m using these integer sequences more and more. They’re proving to be extremely useful in flattening complex recursive data structures and logic. C++14 rules