Edit from 2018: In C++17 the answer to this question is different. You still have to store your arguments in a ::std::tuple
, but when the time comes to call the function ::std::apply
handles unpacking this tuple and calling the function for you. And if you need to use the indices trick for something other than what ::std::apply
does, there's ::std::integer_sequence
and the associated helper function, ::std::make_index_sequence
that you should investigate.
Now back to your C++11/14 answer from way back in 2013.
You have to use ::std::tuple<Args...>
to store it. But then the question is how to unpack it when you need it. For that you need to use a technique called 'indices'.
So, here is a link to a place where I've done approximately what you're looking to do. The most relevant class here that's sort of the centerpiece is suspended_call
.
https://bitbucket.org/omnifarious/sparkles/src/tip/sparkles/deferred.hpp?at=default
In just a bit, I'll extract the most relevant bits and put them in terms of your code.
This line:
auto saved_args = ::std::make_tuple(::std::move(args)...);
saves the arguments into a tuple. I used ::std::move
there, and I think that's the right thing to do. But it's possible I'm wrong and I should use ::std::forward
. I've never been clear on the exact difference aside from signaling intent.
The code that actually does the call with the saved arguments can be found here. Now that code is fairly specific to exactly what I'm doing. The bit that implements the indices trick involves creating a pack of integers that maps to the indices to use as arguments the ::std::get<I>
template. Once you have this pack of integers, you can then use it to expand the call to ::std::get
to get all the tuple elements as individual arguments.
I'll try to come up with code that does that in a relatively straightforward way:
#include <tuple>
#include <cstddef>
#include <string>
#include <utility>
template < ::std::size_t... Indices>
struct indices {};
template < ::std::size_t N, ::std::size_t... Is>
struct build_indices : build_indices<N-1, N-1, Is...>
{};
template < ::std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...>
{};
template <typename FuncT, typename ArgTuple, ::std::size_t... Indices>
auto call(const FuncT &f, ArgTuple &&args, const indices<Indices...> &)
-> decltype(f(::std::get<Indices>(::std::forward<ArgTuple>(args))...))
{
return ::std::move(f(::std::get<Indices>(::std::forward<ArgTuple>(args))...));
}
template <typename FuncT, typename ArgTuple>
auto call(const FuncT &f, ArgTuple &&args)
-> decltype(call(f, args,
build_indices< ::std::tuple_size<ArgTuple>::value>{}))
{
const build_indices< ::std::tuple_size<ArgTuple>::value> indices;
return ::std::move(call(f, ::std::move(args), indices));
}
int myfunc(::std::string name, const unsigned int foo)
{
return 0;
}
int foo(::std::tuple< ::std::string, const unsigned int> saved_args)
{
return call(myfunc, ::std::move(saved_args));
}
A lot of this code was borrowed from this page on the indices trick.
Also, that's sort of a sample that you will have to adapt slightly to your specific situation. Basically, just call call(nestFunc, saved_args)
somewhere.
std::tuple<Args...>
- also,std::bind
andstd::function
and all that fun stuff. – Carltoncarly