una tuplas tupla que c++ templates c++11 tuples

c++ - tuplas - que es una tupla



Plantilla de tupla: llamar a una funciĆ³n en cada elemento (6)

Además de la respuesta de @M. Alaggan, si necesita llamar a una función en los elementos de la tupla por orden de su apariencia en la tupla, en C ++ 17 también puede usar una expresión de plegado como esta:

std::apply([](auto& ...x){(..., some_function(x));}, the_tuple);

( ejemplo vivo ).

Mi pregunta está en el código:

template<typename... Ts> struct TupleOfVectors { std::tuple<std::vector<Ts>...> tuple; void do_something_to_each_vec() { //Question: I want to do this: // "for each (N)": do_something_to_vec<N>() //How? } template<size_t N> void do_something_to_vec() { auto &vec = std::get<N>(tuple); //do something to vec } };


Aquí hay un enfoque que puede funcionar bien en su caso:

template<typename... Ts> struct TupleOfVectors { std::tuple<std::vector<Ts>...> tuple; void do_something_to_each_vec() { // First template parameter is just a dummy. do_something_to_each_vec_helper<0,Ts...>(); } template<size_t N> void do_something_to_vec() { auto &vec = std::get<N>(tuple); //do something to vec } private: // Anchor for the recursion template <int> void do_something_to_each_vec_helper() { } // Execute the function for each template argument. template <int,typename Arg,typename...Args> void do_something_to_each_vec_helper() { do_something_to_each_vec_helper<0,Args...>(); do_something_to_vec<sizeof...(Args)>(); } };

Lo único que está un poco desordenado aquí es el parámetro de plantilla int dummy adicional para do_something_to_each_vec_helper . Es necesario hacer que do_something_to_each_vec_helper sea una plantilla cuando no queden argumentos. Si tuviera otro parámetro de plantilla que quisiera usar, podría usarlo allí.


En C ++ 17 puedes hacer esto:

std::apply([](auto ...x){std::make_tuple(some_function(x)...);} , the_tuple);

some_function que some_function tiene sobrecargas adecuadas para todos los tipos en la tupla.

Esto ya funciona en Clang ++ 3.9, usando std :: experimental :: apply.


Estaba probando con tuplas y metaprogramas y encontré el hilo actual. Creo que mi trabajo puede inspirar a otra persona, aunque me gusta la solución de @Andy.

De todos modos, solo diviértete!

#include <tuple> #include <type_traits> #include <iostream> #include <sstream> #include <functional> template<std::size_t I = 0, typename Tuple, typename Func> typename std::enable_if< I != std::tuple_size<Tuple>::value, void >::type for_each(const Tuple& tuple, Func&& func) { func(std::get<I>(tuple)); for_each<I + 1>(tuple, func); } template<std::size_t I = 0, typename Tuple, typename Func> typename std::enable_if< I == std::tuple_size<Tuple>::value, void >::type for_each(const Tuple& tuple, Func&& func) { // do nothing } struct print { template<typename T> void operator () (T&& t) { std::cout << t << std::endl; } }; template<typename... Params> void test(Params&& ... params) { int sz = sizeof...(params); std::tuple<Params...> values(std::forward<Params>(params)...); for_each(values, print() ); } class MyClass { public: MyClass(const std::string& text) : m_text(text) { } friend std::ostream& operator <<(std::ostream& stream, const MyClass& myClass) { stream << myClass.m_text; return stream; } private: std::string m_text; }; int main() { test(1, "hello", 3.f, 4, MyClass("I don''t care") ); }


Puede hacerlo fácilmente con algunos índices de maquinaria. Dada una gen_seq para generar secuencias de enteros en tiempo de compilación (encapsuladas por la plantilla de clase seq ):

namespace detail { template<int... Is> struct seq { }; template<int N, int... Is> struct gen_seq : gen_seq<N - 1, N - 1, Is...> { }; template<int... Is> struct gen_seq<0, Is...> : seq<Is...> { }; }

Y las siguientes plantillas de funciones:

#include <tuple> namespace detail { template<typename T, typename F, int... Is> void for_each(T&& t, F f, seq<Is...>) { auto l = { (f(std::get<Is>(t)), 0)... }; } } template<typename... Ts, typename F> void for_each_in_tuple(std::tuple<Ts...> const& t, F f) { detail::for_each(t, f, detail::gen_seq<sizeof...(Ts)>()); }

Puedes usar la función for_each_in_tuple arriba de esta manera:

#include <string> #include <iostream> struct my_functor { template<typename T> void operator () (T&& t) { std::cout << t << std::endl; } }; int main() { std::tuple<int, double, std::string> t(42, 3.14, "Hello World!"); for_each_in_tuple(t, my_functor()); }

Aquí hay un ejemplo en vivo .

En tu situación concreta, así es como puedes usarlo:

template<typename... Ts> struct TupleOfVectors { std::tuple<std::vector<Ts>...> t; void do_something_to_each_vec() { for_each_in_tuple(t, tuple_vector_functor()); } struct tuple_vector_functor { template<typename T> void operator () (T const &v) { // Do something on the argument vector... } }; };

Y una vez más, aquí hay un ejemplo en vivo .


Si no está especialmente vinculado a una solución en forma de plantilla de función genérica "para cada", puede utilizar una como esta:

#ifndef TUPLE_OF_VECTORS_H #define TUPLE_OF_VECTORS_H #include <vector> #include <tuple> #include <iostream> template<typename... Ts> struct TupleOfVectors { std::tuple<std::vector<Ts>...> tuple; template<typename ...Args> TupleOfVectors(Args... args) : tuple(args...){} void do_something_to_each_vec() { do_something_to_vec(tuple); } template<size_t I = 0, class ...P> typename std::enable_if<I == sizeof...(P)>::type do_something_to_vec(std::tuple<P...> &) {} template<size_t I = 0, class ...P> typename std::enable_if<I < sizeof...(P)>::type do_something_to_vec(std::tuple<P...> & parts) { auto & part = std::get<I>(tuple); // Doing something... std::cout << "vector[" << I << "][0] = " << part[0] << std::endl; do_something_to_vec<I + 1>(parts); } }; #endif // EOF

Un programa de prueba, construido con GCC 4.7.2 y clang 3.2:

#include "tuple_of_vectors.h" using namespace std; int main() { TupleOfVectors<int,int,int,int> vecs(vector<int>(1,1), vector<int>(2,2), vector<int>(3,3), vector<int>(4,4)); vecs.do_something_to_each_vec(); return 0; }

El mismo estilo de recursión se puede utilizar en una plantilla de función genérica "for_each" sin aparatos de índices auxiliares:

#ifndef FOR_EACH_IN_TUPLE_H #define FOR_EACH_IN_TUPLE_H #include <type_traits> #include <tuple> #include <cstddef> template<size_t I = 0, typename Func, typename ...Ts> typename std::enable_if<I == sizeof...(Ts)>::type for_each_in_tuple(std::tuple<Ts...> &, Func) {} template<size_t I = 0, typename Func, typename ...Ts> typename std::enable_if<I < sizeof...(Ts)>::type for_each_in_tuple(std::tuple<Ts...> & tpl, Func func) { func(std::get<I>(tpl)); for_each_in_tuple<I + 1>(tpl,func); } #endif //EOF

Y un programa de prueba para eso:

#include "for_each_in_tuple.h" #include <iostream> struct functor { template<typename T> void operator () (T&& t) { std::cout << t << std::endl; } }; int main() { auto tpl = std::make_tuple(1,2.0,"Three"); for_each_in_tuple(tpl,functor()); return 0; }