One way would be to write a functor in the Haskell sense. Well a variardic one, which isn't very Haskell.
Write a function of signature (Ts...)->( ((Ts...)->X) -> X )
. Ie a function that takes a pack, and returns a function. The returned function can take a function taking that pack and evaluate it.
template<class...Ts>
auto make_functor(Ts&&...ts); // TODO
Once we have that we can solve your problem easily.
template<class ...A>
auto test(A&& ...a) {
return [unpack_a=make_functor(std::forward<A>(a)...)]() mutable
{
return unpack_a([&](auto&&...a){
// here you have access to a...
return sizeof...(a);
});
};
}
test
takes a pack, and returns a function that returns the size of that pack (well, does anything with the pack).
make_functor
is not easy: basically, we write a manual lambda, storing the args in a tuple, and unpacking the musing the indexes trick in an operator ().
In effect, we do the pack storing and unpacking once in a manual pseudo-lambda class, then get to reuse it later.
On second thought, it may be better to write a delayed apply that takes a tuple, stores it, then uses std::apply
later.
template<class...Ts>
auto delayed_apply(std::tuple<Ts...> tup){
return [tup=std::move(tup)](auto&&f)->decltype(auto) mutable{
return std::experimental::apply(decltype(f)(f), std::move(tup));
};
}
which lets the value/refness of parameters be not lost!
template<class ...A>
auto test(A&& ...a) {
return [unpack_a=delayed_apply(std::forward_as_tuple(std::forward<A>(a)...))]() mutable
{
return unpack_a([&](auto&&...a){
// here you have access to a...
return sizeof...(a);
});
};
}
this does require std::experimental::apply
.
If you want to store rvalues and leave lvalues as references:
unpack_a=delayed_apply(std::tuple<A...>(std::forward<A>(a)...))
If you want to store both l and r values:
unpack_a=delayed_apply(std::make_tuple(std::forward<A>(a)...))
as you can see, this approach gives lots of control.
If you need a std::experimental::apply
, there are reference implementations: better those than anything I write on a smartphone.
Note that make_functor
can be written in terms of delayed_apply
, but the opposite is ... not as true.
In case you are confused, unpack_a
takes a lambda and unpacks the tuple used to create unpack_a
into it. Basically we store one object that is the entire pack, then unpack it when we need it inside the body of the lambda.
A longer delayed_apply
that handles both const and non-const and maybe even rvalue overloads may be required if you want the unpacking to work "more than once" sometimss and "only once" other times. It will have to return a class, not a lambda. Annoying. Made the example code work, I think, still not compiling.
Fortunetally this kind of thing is write once, use many.