Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template tuple - calling a function on each element

My question is in the code:

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   } }; 
like image 937
7cows Avatar asked May 05 '13 17:05

7cows


1 Answers

You can quite easily do that with some indices machinery. Given a meta-function gen_seq for generating compile-time integer sequences (encapsulated by the seq class template):

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

And the following function templates:

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

You can use the for_each_in_tuple function above this way:

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

Here is a live example.

In your concrete situation, this is how you could use it:

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

And once again, here is a live example.

Update

If you're using C++14 or later, you can replace the seq and gen_seq classes above with std::integer_sequence like so:

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

If you're using C++17 or later you can do this (from this comment below):

std::apply([](auto ...x){std::make_tuple(some_function(x)...);} , the_tuple); 
like image 169
Andy Prowl Avatar answered Sep 17 '22 20:09

Andy Prowl