Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

get part of std::tuple

Tags:

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

like image 581
RiaD Avatar asked Dec 20 '11 00:12

RiaD


4 Answers

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)

like image 93
kennytm Avatar answered Sep 18 '22 20:09

kennytm


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); } 
like image 24
Adam Mitz Avatar answered Sep 19 '22 20:09

Adam Mitz


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);
}
like image 39
Jarod42 Avatar answered Sep 21 '22 20:09

Jarod42


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.

like image 20
Nikos Athanasiou Avatar answered Sep 21 '22 20:09

Nikos Athanasiou