tuple geeksforgeeks c++ templates c++11 variadic-templates

geeksforgeeks - tuple c++



C++ 11: puedo pasar de múltiples args a tuple, pero ¿puedo pasar de tuple a multiple args? (2)

Posible duplicado:
¿Cómo puedo expandir una tupla en los argumentos de la función de plantilla variadic?
"Desempaquetar" una tupla para llamar a un puntero de función coincidente

En las plantillas de C ++ 11, ¿hay alguna manera de usar una tupla como argumento individual de una función (posiblemente una plantilla)?

Ejemplo:
Digamos que tengo esta función:

void foo(int a, int b) { }

Y tengo la tuple auto bar = std::make_tuple(1, 2) .

¿Puedo usar eso para llamar a foo(1, 2) de forma temporal?

No me refiero simplemente a foo(std::get<0>(bar), std::get<1>(bar)) ya que quiero hacer esto en una plantilla que no conoce el número de argumentos.

Un ejemplo más completo:

template<typename Func, typename... Args> void caller(Func func, Args... args) { auto argtuple = std::make_tuple(args...); do_stuff_with_tuple(argtuple); func(insert_magic_here(argtuple)); // <-- this is the hard part }

Debo señalar que preferiría no crear una plantilla que funcione para una arg, otra que funcione para dos, etc.


Cree una "tupla de índice" (una tupla de enteros en tiempo de compilación) y luego reenvíela a otra función que deduzca los índices como un paquete de parámetros y los use en una expansión de paquete para llamar a std::get en la tupla:

#include <redi/index_tuple.h> template<typename Func, typename Tuple, unsigned... I> void caller_impl(Func func, Tuple&& t, redi::index_tuple<I...>) { func(std::get<I>(t)...); } template<typename Func, typename... Args> void caller(Func func, Args... args) { auto argtuple = std::make_tuple(args...); do_stuff_with_tuple(argtuple); typedef redi::to_index_tuple<Args...> indices; caller_impl(func, argtuple, indices()); }

Mi implementación de index_tuple está en https://gitlab.com/redistd/redistd/blob/master/include/redi/index_tuple.h pero depende de los alias de las plantillas, así que si tu compilador no admite eso necesitarás modificar usar "template typedefs" tipo C ++ 03 y reemplazar las últimas dos líneas de la caller con

typedef typename redi::make_index_tuple<sizeof...(Args)>::type indices; caller_impl(func, argtuple, indices());

Una utilidad similar se estandarizó como std::index_sequence en C ++ 14 (vea index_seq.h para una implementación independiente de C ++ 11).


Pruebe algo como esto:

// implementation details, users never invoke these directly namespace detail { template <typename F, typename Tuple, bool Done, int Total, int... N> struct call_impl { static void call(F f, Tuple && t) { call_impl<F, Tuple, Total == 1 + sizeof...(N), Total, N..., sizeof...(N)>::call(f, std::forward<Tuple>(t)); } }; template <typename F, typename Tuple, int Total, int... N> struct call_impl<F, Tuple, true, Total, N...> { static void call(F f, Tuple && t) { f(std::get<N>(std::forward<Tuple>(t))...); } }; } // user invokes this template <typename F, typename Tuple> void call(F f, Tuple && t) { typedef typename std::decay<Tuple>::type ttype; detail::call_impl<F, Tuple, 0 == std::tuple_size<ttype>::value, std::tuple_size<ttype>::value>::call(f, std::forward<Tuple>(t)); }

Ejemplo:

#include <cstdio> int main() { auto t = std::make_tuple("%d, %d, %d/n", 1,2,3); call(std::printf, t); }

Con algo de magia extra y usando std::result_of , probablemente también puedas hacer que la cosa entera devuelva el valor de retorno correcto.