get part of std::tuple
With help of a compile-time integer list:
#include <cstdlib>
template <size_t... n>
struct ct_integers_list {
template <size_t m>
struct push_back
{
typedef ct_integers_list<n..., m> type;
};
};
template <size_t max>
struct ct_iota_1
{
typedef typename ct_iota_1<max-1>::type::template push_back<max>::type type;
};
template <>
struct ct_iota_1<0>
{
typedef ct_integers_list<> type;
};
We could construct the tail simply by parameter-pack expansion:
#include <tuple>
template <size_t... indices, typename Tuple>
auto tuple_subset(const Tuple& tpl, ct_integers_list<indices...>)
-> decltype(std::make_tuple(std::get<indices>(tpl)...))
{
return std::make_tuple(std::get<indices>(tpl)...);
// this means:
// make_tuple(get<indices[0]>(tpl), get<indices[1]>(tpl), ...)
}
template <typename Head, typename... Tail>
std::tuple<Tail...> tuple_tail(const std::tuple<Head, Tail...>& tpl)
{
return tuple_subset(tpl, typename ct_iota_1<sizeof...(Tail)>::type());
// this means:
// tuple_subset<1, 2, 3, ..., sizeof...(Tail)-1>(tpl, ..)
}
Usage:
#include <cstdio>
int main()
{
auto a = std::make_tuple(1, "hello", 7.9);
auto b = tuple_tail(a);
const char* s = nullptr;
double d = 0.0;
std::tie(s, d) = b;
printf("%s %g\n", s, d);
// prints: hello 7.9
return 0;
}
(On ideone: http://ideone.com/Tzv7v; the code works in g++ 4.5 to 4.7 and clang++ 3.0)
There may be an easier way, but this is a start. The "tail" function template returns a copied tuple with all values of the original except the first. This compiles with GCC 4.6.2 in C++0x-mode.
template<size_t I>
struct assign {
template<class ResultTuple, class SrcTuple>
static void x(ResultTuple& t, const SrcTuple& tup) {
std::get<I - 1>(t) = std::get<I>(tup);
assign<I - 1>::x(t, tup);
}
};
template<>
struct assign<1> {
template<class ResultTuple, class SrcTuple>
static void x(ResultTuple& t, const SrcTuple& tup) {
std::get<0>(t) = std::get<1>(tup);
}
};
template<class Tup> struct tail_helper;
template<class Head, class... Tail>
struct tail_helper<std::tuple<Head, Tail...>> {
typedef typename std::tuple<Tail...> type;
static type tail(const std::tuple<Head, Tail...>& tup) {
type t;
assign<std::tuple_size<type>::value>::x(t, tup);
return t;
}
};
template<class Tup>
typename tail_helper<Tup>::type tail(const Tup& tup) {
return tail_helper<Tup>::tail(tup);
}
With C++17, you can use std::apply
:
template <typename Head, typename... Tail>
std::tuple<Tail...> tuple_tail(const std::tuple<Head, Tail...>& t)
{
return apply([](auto head, auto... tail) {
return std::make_tuple(tail...)};
}, t);
}