Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11: I can go from multiple args to tuple, but can I go from tuple to multiple args? [duplicate]

Possible Duplicate:
How do I expand a tuple into variadic template function's arguments?
“unpacking” a tuple to call a matching function pointer

In C++11 templates, is there a way to use a tuple as the individual args of a (possibly template) function?

Example:
Let's say I have this function:

void foo(int a, int b)   {   } 

And I have the tuple auto bar = std::make_tuple(1, 2).

Can I use that to call foo(1, 2) in a templaty way?

I don't mean simply foo(std::get<0>(bar), std::get<1>(bar)) since I want to do this in a template that doesn't know the number of args.

More complete example:

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   } 

I should note that I'd prefer to not create one template that works for one arg, another that works for two, etc…

like image 978
Thomas Avatar asked May 26 '12 12:05

Thomas


2 Answers

Try something like this:

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

Example:

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

With some extra magic and using std::result_of, you can probably also make the entire thing return the correct return value.

like image 76
Kerrek SB Avatar answered Sep 17 '22 21:09

Kerrek SB


Create an "index tuple" (a tuple of compile-time integers) then forward to another function that deduces the indices as a parameter pack and uses them in a pack expansion to call std::get on the tuple:

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

My implementation of index_tuple is at https://gitlab.com/redistd/redistd/blob/master/include/redi/index_tuple.h but it relies on template aliases so if your compiler doesn't support that you'd need to modify it to use C++03-style "template typedefs" and replace the last two lines of caller with

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

A similar utility was standardised as std::index_sequence in C++14 (see index_seq.h for a standalone C++11 implementation).

like image 40
Jonathan Wakely Avatar answered Sep 17 '22 21:09

Jonathan Wakely