tuple make_tuple example create c++ g++ c++11 tuples

c++ - make_tuple - obtener parte de std:: tuple



tuple c++ example (6)

Con C ++ 17, puedes usar 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); }

Tengo una tupla de tamaño desconocido (es una plantilla de método)

¿Es la forma de obtener parte de esto? (Necesito tirar el primer elemento)

Por ejemplo, tengo tuple<int,int,int>(7,12,42) . Quiero tuple<int,int>(12,42) aquí


Con la ayuda de una lista de enteros en tiempo de compilación:

#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; };

Podríamos construir la cola simplemente por la expansión del paquete de parámetros:

#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, ..) }

Uso:

#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; }

(En ideone: http://ideone.com/Tzv7v ; el código funciona en g ++ 4.5 a 4.7 y clang ++ 3.0)


Hice algunas modificaciones al código de Adam que eliminaría los primeros N argumentos de la tupla, además de crear una nueva tupla con solo los últimos tipos N ... Aquí está el código completo (nota: si alguien decide hacer +1 mi responda, también, por favor, responda con +1 la respuesta de Adam, ya que es en lo que se basa este código, y no deseo restarle crédito a su contribución) :

//create a struct that allows us to create a new tupe-type with the first //N types truncated from the front template<size_t N, typename Tuple_Type> struct tuple_trunc {}; template<size_t N, typename Head, typename... Tail> struct tuple_trunc<N, std::tuple<Head, Tail...>> { typedef typename tuple_trunc<N-1, std::tuple<Tail...>>::type type; }; template<typename Head, typename... Tail> struct tuple_trunc<0, std::tuple<Head, Tail...>> { typedef std::tuple<Head, Tail...> type; }; /*-------Begin Adam''s Code----------- Note the code has been slightly modified ... I didn''t see the need for the extra variadic templates in the "assign" structure. Hopefully this doesn''t break something I didn''t forsee */ template<size_t N, size_t I> struct assign { template<class ResultTuple, class SrcTuple> static void x(ResultTuple& t, const SrcTuple& tup) { std::get<I - N>(t) = std::get<I>(tup); assign<N, I - 1>::x(t, tup); //this offsets the assignment index by N } }; template<size_t N> struct assign<N, 1> { template<class ResultTuple, class SrcTuple> static void x(ResultTuple& t, const SrcTuple& tup) { std::get<0>(t) = std::get<1>(tup); } }; template<size_t TruncSize, class Tup> struct th2; //modifications to this class change "type" to the new truncated tuple type //as well as modifying the template arguments to assign template<size_t TruncSize, class Head, class... Tail> struct th2<TruncSize, std::tuple<Head, Tail...>> { typedef typename tuple_trunc<TruncSize, std::tuple<Head, Tail...>>::type type; static type tail(const std::tuple<Head, Tail...>& tup) { type t; assign<TruncSize, std::tuple_size<type>::value>::x(t, tup); return t; } }; template<size_t TruncSize, class Tup> typename th2<TruncSize, Tup>::type tail(const Tup& tup) { return th2<TruncSize, Tup>::tail(tup); } //a small example int main() { std::tuple<double, double, int, double> test(1, 2, 3, 4); tuple_trunc<2, std::tuple<double, double, int, double>>::type c = tail<2>(test); return 0; }


Puede haber una manera más fácil, pero esto es un comienzo. La plantilla de la función "cola" devuelve una tupla copiada con todos los valores del original, excepto el primero. Esto compila con GCC 4.6.2 en modo C ++ 0x.

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); }


Una operación de segmento de tupla (que también funciona para std::array y std::pair ) se puede definir de esta manera (se requiere C ++ 14):

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>{}); }

Y un subconjunto arbitrario de una tupla t se puede obtener así:

tuple_slice<I1, I2>(t);

Donde [I1, I2) es el rango exclusivo del subconjunto y el valor de retorno es una tupla de referencias o valores dependiendo de si la tupla de entrada es un valor de l o un valor de r, respectivamente (en mi blog se puede encontrar una explicación detallada).


Por favor no lo uses!

  • Esto es [probablemente] un comportamiento no especificado. Podría dejar de funcionar en cualquier momento.
  • Además, existe la posibilidad de problemas de relleno (es decir, puede funcionar para int pero puede fallar para su tipo).

Ver comentarios para la discusión. Estoy dejando esta respuesta solo como referencia.

Aún más simple:

tuple<int,int,int> origin{7,12,42}; tuple<int, int> &tail1 = (tuple<int, int>&)origin; tuple<int> &tail2 = (tuple<int>&)origin; cout << "tail1: {" << get<0>(tail1) << ", " << get<1>(tail1) << "}" << endl; cout << "tail2: {" << get<0>(tail2) << "}" << endl;

Tengo:

tail1: {12, 42} tail2: {42}

No estoy seguro de que esto no sea un comportamiento no especificado. Funciona para mí: Fedora 20 y

❯ clang --version clang version 3.3 (tags/RELEASE_33/final) Target: x86_64-redhat-linux-gnu Thread model: posix ❯ gcc --version gcc (GCC) 4.8.2 20131212 (Red Hat 4.8.2-7) Copyright (C) 2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Referencias: artículo en voidnish.wordpress.com/ .