Consider the case of a templated function with variadic template arguments:
template<typename Tret, typename... T> Tret func(const T&... t);
Now, I have a tuple t
of values. How do I call func()
using the tuple values as arguments?
I've read about the bind()
function object, with call()
function, and also the apply()
function in different some now-obsolete documents. The GNU GCC 4.4 implementation seems to have a call()
function in the bind()
class, but there is very little documentation on the subject.
Some people suggest hand-written recursive hacks, but the true value of variadic template arguments is to be able to use them in cases like above.
Does anyone have a solution to is, or hint on where to read about it?
I find this to be the most elegant solution (and it is optimally forwarded):
Example usage:
Unfortunately GCC (4.6 at least) fails to compile this with "sorry, unimplemented: mangling overload" (which simply means that the compiler doesn't yet fully implement the C++11 spec), and since it uses variadic templates, it wont work in MSVC, so it is more or less useless. However, once there is a compiler that supports the spec, it will be the best approach IMHO. (Note: it isn't that hard to modify this so that you can work around the deficiencies in GCC, or to implement it with Boost Preprocessor, but it ruins the elegance, so this is the version I am posting.)GCC 4.7 now supports this code just fine.
Edit: Added forward around actual function call to support rvalue reference form *this in case you are using clang (or if anybody else actually gets around to adding it).
Edit: Added missing forward around the function object in the non-member apply function's body. Thanks to pheedbaq for pointing out that it was missing.
Edit: And here is the C++14 version just since it is so much nicer (doesn't actually compile yet):
Here is a version for member functions (not tested very much!):
In C++17 you can do this:
This already works in Clang++ 3.9, using std::experimental::apply.
Responding to the comment saying that this won't work if
the_function
is templated, the following is a work-around:This work around is a simplified solution to the general problem of passing overload sets and function template where a function would be expected. The general solution (one that is taking care of perfect-forwarding, constexpr-ness, and noexcept-ness) is presented here: https://blog.tartanllama.xyz/passing-overload-sets/.
This is adapted from the C++14 draft using index_sequence. I might propose to have apply in a future standard (TS).
1) if you have a readymade parameter_pack structure as function argument, you can just use std::tie like this:
2) if you don't have a readymade parampack arg, you'll have to unwind the tuple like this
In C++ there is many ways of expanding/unpacking tuple and apply those tuple elements to a variadic template function. Here is a small helper class which creates index array. It is used a lot in template metaprogramming:
Now the code which does the job is not that big:
Test is shown bellow:
I'm not big expert in other languages, but I guess that if these languages do not have such functionality in their menu, there is no way to do that. At least with C++ you can, and I think it is not so much complicated...
Extending on @David's solution, you can write a recursive template that
integer_sequence
semanticsint N
to count recursive iterationsE.g.:
Alternatively if your functor is not defined at compile-time (e.g., a non-
constexpr
functor instance, or a lambda expression), you can use it as a function parameter instead of a class template parameter, and in fact remove the containing class entirely:For pointer-to-member-function callables, you can adjust either of the above code pieces similarly as in @David's answer.
Explanation
In reference to the second piece of code, there are two template functions: the first one takes the functor
func
, the tuplet
with typesT...
, and a parameter packargs
of typesArgs_tmp...
. When called, it recursively adds the objects fromt
to the parameter pack one at a time, from beginning (0
) to end, and calls the function again with the new incremented parameter pack.The second function's signature is almost identical to the first, except that it uses type
T...
for the parameter packargs
. Thus, onceargs
in the first function is completely filled with the values fromt
, it's type will beT...
(in psuedo-code,typeid(T...) == typeid(Args_tmp...)
), and thus the compiler will instead call the second overloaded function, which in turn callsfunc(args...)
.The code in the static functor example works identically, with the functor instead used as a class template argument.