I have a tuple of unknown size (it's template parametr of method)
Is it way to get part of it (I need throw away first element of it)
For example, I have tuple<int,int,int>(7,12,42)
. I want tuple<int,int>(12,42)
here
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);
}
A tuple slice operation (that also works for std::array
and std::pair
) can be defined like this (C++14 required):
namespace detail
{
template <std::size_t Ofst, class Tuple, std::size_t... I>
constexpr auto slice_impl(Tuple&& t, std::index_sequence<I...>)
{
return std::forward_as_tuple(
std::get<I + Ofst>(std::forward<Tuple>(t))...);
}
}
template <std::size_t I1, std::size_t I2, class Cont>
constexpr auto tuple_slice(Cont&& t)
{
static_assert(I2 >= I1, "invalid slice");
static_assert(std::tuple_size<std::decay_t<Cont>>::value >= I2,
"slice index out of bounds");
return detail::slice_impl<I1>(std::forward<Cont>(t),
std::make_index_sequence<I2 - I1>{});
}
And an arbitrary subset of a tuple t
can be obtained like so :
tuple_slice<I1, I2>(t);
Where [I1, I2)
is the exclusive range of the subset and the return value is a tuple of references to the original tuple. If you want a copying slice operation substitute forward_as_tuple
with make_tuple
in slice_impl
. A thorough elaboration can be found in my blog.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With