Expanding a tuple with perfect forwarding [duplicate] - c++
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?
In C++17 you can do this:
std::apply(the_function, the_tuple);
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:
#include <tuple>
template <typename T, typename U> void my_func(T &&t, U &&u) {}
int main(int argc, char *argv[argc]) {
std::tuple<int, float> my_tuple;
std::apply([](auto &&... args) { my_func(args...); }, my_tuple);
return 0;
}
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/.
Here's my code if anyone is interested
Basically at compile time the compiler will recursively unroll all arguments in various inclusive function calls <N> -> calls <N-1> -> calls ... -> calls <0> which is the last one and the compiler will optimize away the various intermediate function calls to only keep the last one which is the equivalent of func(arg1, arg2, arg3, ...)
Provided are 2 versions, one for a function called on an object and the other for a static function.
#include <tr1/tuple>
/**
* Object Function Tuple Argument Unpacking
*
* This recursive template unpacks the tuple parameters into
* variadic template arguments until we reach the count of 0 where the function
* is called with the correct parameters
*
* #tparam N Number of tuple arguments to unroll
*
* #ingroup g_util_tuple
*/
template < uint N >
struct apply_obj_func
{
template < typename T, typename... ArgsF, typename... ArgsT, typename... Args >
static void applyTuple( T* pObj,
void (T::*f)( ArgsF... ),
const std::tr1::tuple<ArgsT...>& t,
Args... args )
{
apply_obj_func<N-1>::applyTuple( pObj, f, t, std::tr1::get<N-1>( t ), args... );
}
};
//-----------------------------------------------------------------------------
/**
* Object Function Tuple Argument Unpacking End Point
*
* This recursive template unpacks the tuple parameters into
* variadic template arguments until we reach the count of 0 where the function
* is called with the correct parameters
*
* #ingroup g_util_tuple
*/
template <>
struct apply_obj_func<0>
{
template < typename T, typename... ArgsF, typename... ArgsT, typename... Args >
static void applyTuple( T* pObj,
void (T::*f)( ArgsF... ),
const std::tr1::tuple<ArgsT...>& /* t */,
Args... args )
{
(pObj->*f)( args... );
}
};
//-----------------------------------------------------------------------------
/**
* Object Function Call Forwarding Using Tuple Pack Parameters
*/
// Actual apply function
template < typename T, typename... ArgsF, typename... ArgsT >
void applyTuple( T* pObj,
void (T::*f)( ArgsF... ),
std::tr1::tuple<ArgsT...> const& t )
{
apply_obj_func<sizeof...(ArgsT)>::applyTuple( pObj, f, t );
}
//-----------------------------------------------------------------------------
/**
* Static Function Tuple Argument Unpacking
*
* This recursive template unpacks the tuple parameters into
* variadic template arguments until we reach the count of 0 where the function
* is called with the correct parameters
*
* #tparam N Number of tuple arguments to unroll
*
* #ingroup g_util_tuple
*/
template < uint N >
struct apply_func
{
template < typename... ArgsF, typename... ArgsT, typename... Args >
static void applyTuple( void (*f)( ArgsF... ),
const std::tr1::tuple<ArgsT...>& t,
Args... args )
{
apply_func<N-1>::applyTuple( f, t, std::tr1::get<N-1>( t ), args... );
}
};
//-----------------------------------------------------------------------------
/**
* Static Function Tuple Argument Unpacking End Point
*
* This recursive template unpacks the tuple parameters into
* variadic template arguments until we reach the count of 0 where the function
* is called with the correct parameters
*
* #ingroup g_util_tuple
*/
template <>
struct apply_func<0>
{
template < typename... ArgsF, typename... ArgsT, typename... Args >
static void applyTuple( void (*f)( ArgsF... ),
const std::tr1::tuple<ArgsT...>& /* t */,
Args... args )
{
f( args... );
}
};
//-----------------------------------------------------------------------------
/**
* Static Function Call Forwarding Using Tuple Pack Parameters
*/
// Actual apply function
template < typename... ArgsF, typename... ArgsT >
void applyTuple( void (*f)(ArgsF...),
std::tr1::tuple<ArgsT...> const& t )
{
apply_func<sizeof...(ArgsT)>::applyTuple( f, t );
}
// ***************************************
// Usage
// ***************************************
template < typename T, typename... Args >
class Message : public IMessage
{
typedef void (T::*F)( Args... args );
public:
Message( const std::string& name,
T& obj,
F pFunc,
Args... args );
private:
virtual void doDispatch( );
T* pObj_;
F pFunc_;
std::tr1::tuple<Args...> args_;
};
//-----------------------------------------------------------------------------
template < typename T, typename... Args >
Message<T, Args...>::Message( const std::string& name,
T& obj,
F pFunc,
Args... args )
: IMessage( name ),
pObj_( &obj ),
pFunc_( pFunc ),
args_( std::forward<Args>(args)... )
{
}
//-----------------------------------------------------------------------------
template < typename T, typename... Args >
void Message<T, Args...>::doDispatch( )
{
try
{
applyTuple( pObj_, pFunc_, args_ );
}
catch ( std::exception& e )
{
}
}
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:
// ------------- UTILITY---------------
template<int...> struct index_tuple{};
template<int I, typename IndexTuple, typename... Types>
struct make_indexes_impl;
template<int I, int... Indexes, typename T, typename ... Types>
struct make_indexes_impl<I, index_tuple<Indexes...>, T, Types...>
{
typedef typename make_indexes_impl<I + 1, index_tuple<Indexes..., I>, Types...>::type type;
};
template<int I, int... Indexes>
struct make_indexes_impl<I, index_tuple<Indexes...> >
{
typedef index_tuple<Indexes...> type;
};
template<typename ... Types>
struct make_indexes : make_indexes_impl<0, index_tuple<>, Types...>
{};
Now the code which does the job is not that big:
// ----------UNPACK TUPLE AND APPLY TO FUNCTION ---------
#include <tuple>
#include <iostream>
using namespace std;
template<class Ret, class... Args, int... Indexes >
Ret apply_helper( Ret (*pf)(Args...), index_tuple< Indexes... >, tuple<Args...>&& tup)
{
return pf( forward<Args>( get<Indexes>(tup))... );
}
template<class Ret, class ... Args>
Ret apply(Ret (*pf)(Args...), const tuple<Args...>& tup)
{
return apply_helper(pf, typename make_indexes<Args...>::type(), tuple<Args...>(tup));
}
template<class Ret, class ... Args>
Ret apply(Ret (*pf)(Args...), tuple<Args...>&& tup)
{
return apply_helper(pf, typename make_indexes<Args...>::type(), forward<tuple<Args...>>(tup));
}
Test is shown bellow:
// --------------------- TEST ------------------
void one(int i, double d)
{
std::cout << "function one(" << i << ", " << d << ");\n";
}
int two(int i)
{
std::cout << "function two(" << i << ");\n";
return i;
}
int main()
{
std::tuple<int, double> tup(23, 4.5);
apply(one, tup);
int d = apply(two, std::make_tuple(2));
return 0;
}
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...
I find this to be the most elegant solution (and it is optimally forwarded):
#include <cstddef>
#include <tuple>
#include <type_traits>
#include <utility>
template<size_t N>
struct Apply {
template<typename F, typename T, typename... A>
static inline auto apply(F && f, T && t, A &&... a)
-> decltype(Apply<N-1>::apply(
::std::forward<F>(f), ::std::forward<T>(t),
::std::get<N-1>(::std::forward<T>(t)), ::std::forward<A>(a)...
))
{
return Apply<N-1>::apply(::std::forward<F>(f), ::std::forward<T>(t),
::std::get<N-1>(::std::forward<T>(t)), ::std::forward<A>(a)...
);
}
};
template<>
struct Apply<0> {
template<typename F, typename T, typename... A>
static inline auto apply(F && f, T &&, A &&... a)
-> decltype(::std::forward<F>(f)(::std::forward<A>(a)...))
{
return ::std::forward<F>(f)(::std::forward<A>(a)...);
}
};
template<typename F, typename T>
inline auto apply(F && f, T && t)
-> decltype(Apply< ::std::tuple_size<
typename ::std::decay<T>::type
>::value>::apply(::std::forward<F>(f), ::std::forward<T>(t)))
{
return Apply< ::std::tuple_size<
typename ::std::decay<T>::type
>::value>::apply(::std::forward<F>(f), ::std::forward<T>(t));
}
Example usage:
void foo(int i, bool b);
std::tuple<int, bool> t = make_tuple(20, false);
void m()
{
apply(&foo, t);
}
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):
#include <cstddef>
#include <tuple>
#include <type_traits>
#include <utility>
template<size_t N>
struct Apply {
template<typename F, typename T, typename... A>
static inline auto apply(F && f, T && t, A &&... a) {
return Apply<N-1>::apply(::std::forward<F>(f), ::std::forward<T>(t),
::std::get<N-1>(::std::forward<T>(t)), ::std::forward<A>(a)...
);
}
};
template<>
struct Apply<0> {
template<typename F, typename T, typename... A>
static inline auto apply(F && f, T &&, A &&... a) {
return ::std::forward<F>(f)(::std::forward<A>(a)...);
}
};
template<typename F, typename T>
inline auto apply(F && f, T && t) {
return Apply< ::std::tuple_size< ::std::decay_t<T>
>::value>::apply(::std::forward<F>(f), ::std::forward<T>(t));
}
Here is a version for member functions (not tested very much!):
using std::forward; // You can change this if you like unreadable code or care hugely about namespace pollution.
template<size_t N>
struct ApplyMember
{
template<typename C, typename F, typename T, typename... A>
static inline auto apply(C&& c, F&& f, T&& t, A&&... a) ->
decltype(ApplyMember<N-1>::apply(forward<C>(c), forward<F>(f), forward<T>(t), std::get<N-1>(forward<T>(t)), forward<A>(a)...))
{
return ApplyMember<N-1>::apply(forward<C>(c), forward<F>(f), forward<T>(t), std::get<N-1>(forward<T>(t)), forward<A>(a)...);
}
};
template<>
struct ApplyMember<0>
{
template<typename C, typename F, typename T, typename... A>
static inline auto apply(C&& c, F&& f, T&&, A&&... a) ->
decltype((forward<C>(c)->*forward<F>(f))(forward<A>(a)...))
{
return (forward<C>(c)->*forward<F>(f))(forward<A>(a)...);
}
};
// C is the class, F is the member function, T is the tuple.
template<typename C, typename F, typename T>
inline auto apply(C&& c, F&& f, T&& t) ->
decltype(ApplyMember<std::tuple_size<typename std::decay<T>::type>::value>::apply(forward<C>(c), forward<F>(f), forward<T>(t)))
{
return ApplyMember<std::tuple_size<typename std::decay<T>::type>::value>::apply(forward<C>(c), forward<F>(f), forward<T>(t));
}
// Example:
class MyClass
{
public:
void foo(int i, bool b);
};
MyClass mc;
std::tuple<int, bool> t = make_tuple(20, false);
void m()
{
apply(&mc, &MyClass::foo, t);
}
template<typename F, typename Tuple, std::size_t ... I>
auto apply_impl(F&& f, Tuple&& t, std::index_sequence<I...>) {
return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
}
template<typename F, typename Tuple>
auto apply(F&& f, Tuple&& t) {
using Indices = std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>;
return apply_impl(std::forward<F>(f), std::forward<Tuple>(t), Indices());
}
This is adapted from the C++14 draft using index_sequence. I might propose to have apply in a future standard (TS).
All this implementations are good. But due to use of pointer to member function compiler often cannot inline the target function call (at least gcc 4.8 can't, no matter what Why gcc can't inline function pointers that can be determined?)
But things changes if send pointer to member function as template arguments, not as function params:
/// from https://stackoverflow.com/a/9288547/1559666
template<int ...> struct seq {};
template<int N, int ...S> struct gens : gens<N-1, N-1, S...> {};
template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; };
template<typename TT>
using makeSeq = typename gens< std::tuple_size< typename std::decay<TT>::type >::value >::type;
// deduce function return type
template<class ...Args>
struct fn_type;
template<class ...Args>
struct fn_type< std::tuple<Args...> >{
// will not be called
template<class Self, class Fn>
static auto type_helper(Self &self, Fn f) -> decltype((self.*f)(declval<Args>()...)){
//return (self.*f)(Args()...);
return NULL;
}
};
template<class Self, class ...Args>
struct APPLY_TUPLE{};
template<class Self, class ...Args>
struct APPLY_TUPLE<Self, std::tuple<Args...>>{
Self &self;
APPLY_TUPLE(Self &self): self(self){}
template<class T, T (Self::* f)(Args...), class Tuple>
void delayed_call(Tuple &&list){
caller<T, f, Tuple >(forward<Tuple>(list), makeSeq<Tuple>() );
}
template<class T, T (Self::* f)(Args...), class Tuple, int ...S>
void caller(Tuple &&list, const seq<S...>){
(self.*f)( std::get<S>(forward<Tuple>(list))... );
}
};
#define type_of(val) typename decay<decltype(val)>::type
#define apply_tuple(obj, fname, tuple) \
APPLY_TUPLE<typename decay<decltype(obj)>::type, typename decay<decltype(tuple)>::type >(obj).delayed_call< \
decltype( fn_type< type_of(tuple) >::type_helper(obj, &decay<decltype(obj)>::type::fname) ), \
&decay<decltype(obj)>::type::fname \
> \
(tuple);
And ussage:
struct DelayedCall
{
void call_me(int a, int b, int c){
std::cout << a+b+c;
}
void fire(){
tuple<int,int,int> list = make_tuple(1,2,3);
apply_tuple(*this, call_me, list); // even simpler than previous implementations
}
};
Proof of inlinable http://goo.gl/5UqVnC
With small changes, we can "overload" apply_tuple:
#define VA_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
#define VA_NARGS(...) VA_NARGS_IMPL(X,##__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0)
#define VARARG_IMPL_(base, count, ...) base##count(__VA_ARGS__)
#define VARARG_IMPL(base, count, ...) VARARG_IMPL_(base, count, __VA_ARGS__)
#define VARARG(base, ...) VARARG_IMPL(base, VA_NARGS(__VA_ARGS__), __VA_ARGS__)
#define apply_tuple2(fname, tuple) apply_tuple3(*this, fname, tuple)
#define apply_tuple3(obj, fname, tuple) \
APPLY_TUPLE<typename decay<decltype(obj)>::type, typename decay<decltype(tuple)>::type >(obj).delayed_call< \
decltype( fn_type< type_of(tuple) >::type_helper(obj, &decay<decltype(obj)>::type::fname) ), \
&decay<decltype(obj)>::type::fname \
/* ,decltype(tuple) */> \
(tuple);
#define apply_tuple(...) VARARG(apply_tuple, __VA_ARGS__)
...
apply_tuple(obj, call_me, list);
apply_tuple(call_me, list); // call this->call_me(list....)
Plus this is the only one solution which works with templated functions.
1) if you have a readymade parameter_pack structure as function argument, you can just use std::tie like this:
template <class... Args>
void tie_func(std::tuple<Args...> t, Args&... args)
{
std::tie<Args...>(args...) = t;
}
int main()
{
std::tuple<int, double, std::string> t(2, 3.3, "abc");
int i;
double d;
std::string s;
tie_func(t, i, d, s);
std::cout << i << " " << d << " " << s << std::endl;
}
2) if you don't have a readymade parampack arg, you'll have to unwind the tuple like this
#include <tuple>
#include <functional>
#include <iostream>
template<int N>
struct apply_wrap {
template<typename R, typename... TupleArgs, typename... UnpackedArgs>
static R applyTuple( std::function<R(TupleArgs...)>& f, const std::tuple<TupleArgs...>& t, UnpackedArgs... args )
{
return apply_wrap<N-1>::applyTuple( f, t, std::get<N-1>( t ), args... );
}
};
template<>
struct apply_wrap<0>
{
template<typename R, typename... TupleArgs, typename... UnpackedArgs>
static R applyTuple( std::function<R(TupleArgs...)>& f, const std::tuple<TupleArgs...>&, UnpackedArgs... args )
{
return f( args... );
}
};
template<typename R, typename... TupleArgs>
R applyTuple( std::function<R(TupleArgs...)>& f, std::tuple<TupleArgs...> const& t )
{
return apply_wrap<sizeof...(TupleArgs)>::applyTuple( f, t );
}
int fac(int n)
{
int r=1;
for(int i=2; i<=n; ++i)
r *= i;
return r;
}
int main()
{
auto t = std::make_tuple(5);
auto f = std::function<decltype(fac)>(&fac);
cout << applyTuple(f, t);
}
The news does not look good.
Having read over the just-released draft standard, I'm not seeing a built-in solution to this, which does seem odd.
The best place to ask about such things (if you haven't already) is comp.lang.c++.moderated, because some folks involved in drafting the standard post there regularly.
If you check out this thread, someone has the same question (maybe it's you, in which case you're going to find this whole answer a little frustrating!), and a few butt-ugly implementations are suggested.
I just wondered if it would be simpler to make the function accept a tuple, as the conversion that way is easier. But this implies that all functions should accept tuples as arguments, for maximum flexibility, and so that just demonstrates the strangeness of not providing a built-in expansion of tuple to function argument pack.
Update: the link above doesn't work - try pasting this:
http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/750fa3815cdaac45/d8dc09e34bbb9661?lnk=gst&q=tuple+variadic#d8dc09e34bbb9661
How about this:
// Warning: NOT tested!
#include <cstddef>
#include <tuple>
#include <type_traits>
#include <utility>
using std::declval;
using std::forward;
using std::get;
using std::integral_constant;
using std::size_t;
using std::tuple;
namespace detail
{
template < typename Func, typename ...T, typename ...Args >
auto explode_tuple( integral_constant<size_t, 0u>, tuple<T...> const &t,
Func &&f, Args &&...a )
-> decltype( forward<Func>(f)(declval<T const>()...) )
{ return forward<Func>( f )( forward<Args>(a)... ); }
template < size_t Index, typename Func, typename ...T, typename ...Args >
auto explode_tuple( integral_constant<size_t, Index>, tuple<T...> const&t,
Func &&f, Args &&...a )
-> decltype( forward<Func>(f)(declval<T const>()...) )
{
return explode_tuple( integral_constant<size_t, Index - 1u>{}, t,
forward<Func>(f), get<Index - 1u>(t), forward<Args>(a)... );
}
}
template < typename Func, typename ...T >
auto run_tuple( Func &&f, tuple<T...> const &t )
-> decltype( forward<Func>(f)(declval<T const>()...) )
{
return detail::explode_tuple( integral_constant<size_t, sizeof...(T)>{}, t,
forward<Func>(f) );
}
template < typename Tret, typename ...T >
Tret func_T( tuple<T...> const &t )
{ return run_tuple( &func<Tret, T...>, t ); }
The run_tuple function template takes the given tuple and pass its elements individually to the given function. It carries out its work by recursively calling its helper function templates explode_tuple. It's important that run_tuple passes the tuple's size to explode_tuple; that number acts as a counter for how many elements to extract.
If the tuple is empty, then run_tuple calls the first version of explode_tuple with the remote function as the only other argument. The remote function is called with no arguments and we're done. If the tuple is not empty, a higher number is passed to the second version of explode_tuple, along with the remote function. A recursive call to explode_tuple is made, with the same arguments, except the counter number is decreased by one and (a reference to) the last tuple element is tacked on as an argument after the remote function. In a recursive call, either the counter isn't zero, and another call is made with the counter decreased again and the next-unreferenced element is inserted in the argument list after the remote function but before the other inserted arguments, or the counter reaches zero and the remote function is called with all the arguments accumulated after it.
I'm not sure I have the syntax of forcing a particular version of a function template right. I think you can use a pointer-to-function as a function object; the compiler will automatically fix it.
I am evaluating MSVS 2013RC, and it failed to compile some of the previous solutions proposed here in some cases. For example, MSVS will fail to compile "auto" returns if there are too many function parameters, because of a namespace imbrication limit (I sent that info to Microsoft to have it corrected). In other cases, we need access to the function's return, although that can also be done with a lamda: the following two examples give the same result..
apply_tuple([&ret1](double a){ret1 = cos(a); }, std::make_tuple<double>(.2));
ret2 = apply_tuple((double(*)(double))cos, std::make_tuple<double>(.2));
And thanks again to those who posted answers here before me, I wouldn't have gotten to this without it... so here it is:
template<size_t N>
struct apply_impl {
template<typename F, typename T, typename... A>
static inline auto apply_tuple(F&& f, T&& t, A&&... a)
-> decltype(apply_impl<N-1>::apply_tuple(std::forward<F>(f), std::forward<T>(t),
std::get<N-1>(std::forward<T>(t)), std::forward<A>(a)...)) {
return apply_impl<N-1>::apply_tuple(std::forward<F>(f), std::forward<T>(t),
std::get<N-1>(std::forward<T>(t)), std::forward<A>(a)...);
}
template<typename C, typename F, typename T, typename... A>
static inline auto apply_tuple(C*const o, F&& f, T&& t, A&&... a)
-> decltype(apply_impl<N-1>::apply_tuple(o, std::forward<F>(f), std::forward<T>(t),
std::get<N-1>(std::forward<T>(t)), std::forward<A>(a)...)) {
return apply_impl<N-1>::apply_tuple(o, std::forward<F>(f), std::forward<T>(t),
std::get<N-1>(std::forward<T>(t)), std::forward<A>(a)...);
}
};
// This is a work-around for MSVS 2013RC that is required in some cases
#if _MSC_VER <= 1800 /* update this when bug is corrected */
template<>
struct apply_impl<6> {
template<typename F, typename T, typename... A>
static inline auto apply_tuple(F&& f, T&& t, A&&... a)
-> decltype(std::forward<F>(f)(std::get<0>(std::forward<T>(t)), std::get<1>(std::forward<T>(t)), std::get<2>(std::forward<T>(t)),
std::get<3>(std::forward<T>(t)), std::get<4>(std::forward<T>(t)), std::get<5>(std::forward<T>(t)), std::forward<A>(a)...)) {
return std::forward<F>(f)(std::get<0>(std::forward<T>(t)), std::get<1>(std::forward<T>(t)), std::get<2>(std::forward<T>(t)),
std::get<3>(std::forward<T>(t)), std::get<4>(std::forward<T>(t)), std::get<5>(std::forward<T>(t)), std::forward<A>(a)...);
}
template<typename C, typename F, typename T, typename... A>
static inline auto apply_tuple(C*const o, F&& f, T&& t, A&&... a)
-> decltype((o->*std::forward<F>(f))(std::get<0>(std::forward<T>(t)), std::get<1>(std::forward<T>(t)), std::get<2>(std::forward<T>(t)),
std::get<3>(std::forward<T>(t)), std::get<4>(std::forward<T>(t)), std::get<5>(std::forward<T>(t)), std::forward<A>(a)...)) {
return (o->*std::forward<F>(f))(std::get<0>(std::forward<T>(t)), std::get<1>(std::forward<T>(t)), std::get<2>(std::forward<T>(t)),
std::get<3>(std::forward<T>(t)), std::get<4>(std::forward<T>(t)), std::get<5>(std::forward<T>(t)), std::forward<A>(a)...);
}
};
#endif
template<>
struct apply_impl<0> {
template<typename F, typename T, typename... A>
static inline auto apply_tuple(F&& f, T&&, A&&... a)
-> decltype(std::forward<F>(f)(std::forward<A>(a)...)) {
return std::forward<F>(f)(std::forward<A>(a)...);
}
template<typename C, typename F, typename T, typename... A>
static inline auto apply_tuple(C*const o, F&& f, T&&, A&&... a)
-> decltype((o->*std::forward<F>(f))(std::forward<A>(a)...)) {
return (o->*std::forward<F>(f))(std::forward<A>(a)...);
}
};
// Apply tuple parameters on a non-member or static-member function by perfect forwarding
template<typename F, typename T>
inline auto apply_tuple(F&& f, T&& t)
-> decltype(apply_impl<std::tuple_size<typename std::decay<T>::type>::value>::apply_tuple(std::forward<F>(f), std::forward<T>(t))) {
return apply_impl<std::tuple_size<typename std::decay<T>::type>::value>::apply_tuple(std::forward<F>(f), std::forward<T>(t));
}
// Apply tuple parameters on a member function
template<typename C, typename F, typename T>
inline auto apply_tuple(C*const o, F&& f, T&& t)
-> decltype(apply_impl<std::tuple_size<typename std::decay<T>::type>::value>::apply_tuple(o, std::forward<F>(f), std::forward<T>(t))) {
return apply_impl<std::tuple_size<typename std::decay<T>::type>::value>::apply_tuple(o, std::forward<F>(f), std::forward<T>(t));
}
Extending on #David's solution, you can write a recursive template that
Doesn't use the (overly-verbose, imo) integer_sequence semantics
Doesn't use an extra temporary template parameter int N to count recursive iterations
(Optional for static/global functors) uses the functor as a template parameter for compile-time optimizaion
E.g.:
template <class F, F func>
struct static_functor {
template <class... T, class... Args_tmp>
static inline auto apply(const std::tuple<T...>& t, Args_tmp... args)
-> decltype(func(std::declval<T>()...)) {
return static_functor<F,func>::apply(t, args...,
std::get<sizeof...(Args_tmp)>(t));
}
template <class... T>
static inline auto apply(const std::tuple<T...>& t, T... args)
-> decltype(func(args...)) {
return func(args...);
}
};
static_functor<decltype(&myFunc), &myFunc>::apply(my_tuple);
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:
template <class F, class... T, class... Args_tmp>
inline auto apply_functor(F&& func, const std::tuple<T...>& t,
Args_tmp... args) -> decltype(func(std::declval<T>()...)) {
return apply_functor(func, t, args..., std::get<sizeof...(Args_tmp)>(t));
}
template <class F, class... T>
inline auto apply_functor(F&& func, const std::tuple<T...>& t,
T... args) -> decltype(func(args...)) {
return func(args...);
}
apply_functor(&myFunc, my_tuple);
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 tuple t with types T..., and a parameter pack args of types Args_tmp.... When called, it recursively adds the objects from t 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 pack args. Thus, once args in the first function is completely filled with the values from t, it's type will be T... (in psuedo-code, typeid(T...) == typeid(Args_tmp...)), and thus the compiler will instead call the second overloaded function, which in turn calls func(args...).
The code in the static functor example works identically, with the functor instead used as a class template argument.
Why not just wrap your variadic arguments into a tuple class and then use compile time recursion (see link) to retrieve the index you are interested in. I find that unpacking variadic templates into a container or collection may not be type safe w.r.t. heterogeneous types
template<typename... Args>
auto get_args_as_tuple(Args... args) -> std::tuple<Args...>
{
return std::make_tuple(args);
}
This simple solution works for me:
template<typename... T>
void unwrap_tuple(std::tuple<T...>* tp)
{
std::cout << "And here I have the tuple types, all " << sizeof...(T) << " of them" << std::endl;
}
int main()
{
using TupleType = std::tuple<int, float, std::string, void*>;
unwrap_tuple((TupleType*)nullptr); // trick compiler into using template param deduction
}
Related
How to apply an if at compile time in C++
I am trying to write a general static_for implementation that can accept bounds, an increment function & a comparison function to run a loop through. I have been using this construct with simple loops that increment by 1. In that case it is easy to stop the loop unrolling by simply specializing on the IDX & END being equal. However when the increment could be with an arbitrary integer, it is not guaranteed that the IDX & END will always be equal. The if conditional is only evaluated at run time. In the code snippet below I was trying to specialize on the std::false_type which stops the recursion. The integral_constant is constructed by evaluating the std::less functional (which could be substituted by the user for any other evaluation). Unfortunately this comparator functional is also evaluated only at run time and therefore the compiler fails. Could someone advise on how to get this to work? NOTE: Using C++11. template <int idx, int end, typename eval, int count, typename comparator> struct static_for_loop { template <typename Lambda, typename... Args> void operator()(const Lambda& function, Args... args) const { if (comparator()(idx, end)) { std::integral_constant<int, idx> i; function(i, args...); constexpr bool lesser = comparator()(idx + count, end); static_for_loop<idx + count, end, std::integral_constant<bool, lesser>, count, comparator>()(function, args...); } } }; template <int idx, int end, int count, typename comparator> struct static_for_loop<idx, end, std::false_type, count, comparator> { template <typename Lambda, typename... Args> void operator()(const Lambda& function, Args... args) const {} }; template <int idx, int end, int count = 1, typename comparator = std::less<int>> struct static_for { template <typename Lambda, typename... Args> void operator()(const Lambda& function, Args... args) const { static_for_loop<idx, end, std::true_type, count, comparator>()(function, args...); } };
I find it easier to just wrap everything in an object: template <int S, int E, int step> struct iter { auto next() { return iter<std::min(E, S+step), E, step>{}; } }; And then you just have an overload for the case where it's done and the case where it's not: template <int S, int E, int step, class F, class... Args> void for_loop(iter<S, E, step> i, F func, Args... args) { func(S, args...); for_loop(i.next(), func, args...); } template <int E, int step, class F, class... Args> void for_loop(iter<E, E, step>, F, Args... ) { } For instance: // prints 0 4 8 for_loop(iter<0, 10, 4>{}, [](int i){std::cout << i << ' ';}); Alternatively, could use enable_if to differentiate the cases to avoid the need for min: template <int S, int E, int step, class F, class... Args> std::enable_if_t<(S<E)> for_loop(iter<S, E, step>, F func, Args... args) { func(S, args...); for_loop(iter<S+step, E, step>{}, func, args...); } template <int S, int E, int step, class F, class... Args> std::enable_if_t<!(S<E)> for_loop(iter<S, E, step>, F , Args... ) { } YMMV on which you prefer.
You can use sfinae to overcome the problem: template <int idx, int end, typename eval, int count, typename Comparator> struct static_for_loop { template <typename Lambda, typename... Args> auto operator()(Lambda&& function, Args&&... args) const -> std::enable_if_t<Comparator{}(idx, end)> { std::integral_constant<int, idx> i; std::forward<Lambda>(function)(i, std::forward<Args>(args)...); constexpr bool lesser = comparator{}(idx + count, end); static_for_loop< idx + count, END, std::integral_constant<bool, lesser>, count, Comparator >()(std::forward<Lambda>(function), std::forward<Args>(args)...); } // do nothing when false template <typename Lambda, typename... Args> auto operator()(Lambda&& function, Args&&... args) const -> std::enable_if_t<!Comparator{}(idx, end)> { } }; std::enable_if will select the right function with sfinae. It will act as a compile time if. I used perfect forwarding too, as your code didn't work in all case, like passing non copiable or a mutable lambda. Now it will. If you do not have c++14, you can write typename std::enable_if<...>::type instead. Try to use less all uppercase name, it hurts lisibility.
Isn't the problem that you are underspecifying comparator? Just specify your API such that comparator<IDX>::type is std::true_type if the loop should continue for IDX, and stop when it's false_type. Your simple loop case then uses template<int IDX> using Comp = std::integral_constant<bool, (IDX < 5)>`.
perfect forwarding failing for lvalues
I have a utility function which iterates over a tuple, and for each element, calls a function with that element, and finally calls another function with the result of all the tuple elements. To better illustrate: There is a tuple of various types tuple<Foo<int>, Bar<double>, Baz<char>> Each type Foo, Bar and Baz have an implicit interface ClassT::data() which returns a reference to some internal member T&. You have a function with the signature void (int, double, char) The utility iterates over the tuple members, extracting the reference to the internal members, and calls the function with the required parameters. Issue: perfect forwarding I have tried to implement the utility using so-called "universal references" and perfect forwarding, thereby negating the need for multiple lvalue/rvalue and const/non-const overloads. Whilst the parameter to the function is of type template<typename Tuple> auto invoke(Tuple&& tuple) I cannot bind lvalues to it. Why is this? I have asked a similar question leading up to this here which has been solved; however since this is an unrelated issue, I believe this warrants a new question Example on ideone: https://ideone.com/lO5JOB #include <tuple> #include <iostream> // sequence template<size_t...> struct Sequence { }; template<size_t N, size_t... Seq> struct GenerateSequence : GenerateSequence<N - 1, N - 1, Seq...> { }; template<size_t... Seq> struct GenerateSequence<0, Seq...> { using type = Sequence<Seq...>; }; // invoke tuple struct TupleForEachInvoker { template<typename Func, typename ForEachFunc, typename Tuple, size_t... Seq> static auto invoke(Func&& func, ForEachFunc&& forEachFunc, Tuple&& tuple, Sequence<Seq...>) -> decltype(func(forEachFunc(std::get<Seq>(std::forward<Tuple>(tuple)))...)) { return func(forEachFunc(std::get<Seq>(std::forward<Tuple>(tuple)))...); } template<typename Func, typename ForEachFunc, typename... Args> static auto apply(Func&& func, ForEachFunc&& forEachFunc, std::tuple<Args...>&& args) -> decltype(invoke(std::forward<Func>(func), std::forward<ForEachFunc>(forEachFunc), std::forward<std::tuple<Args...>>(args), typename GenerateSequence<sizeof...(Args)>::type())) { return invoke(std::forward<Func>(func), std::forward<ForEachFunc>(forEachFunc), std::forward<std::tuple<Args...>>(args), typename GenerateSequence<sizeof...(Args)>::type()); } }; template<typename Func, typename ForEachFunc, typename Tuple> inline auto invokeWithMemberFromAll(Func&& func, ForEachFunc&& forEachFunc, Tuple&& tuple) -> decltype(TupleForEachInvoker::apply(std::forward<Func>(func), std::forward<ForEachFunc>(forEachFunc), std::forward<Tuple>(tuple))) { return TupleForEachInvoker::apply(std::forward<Func>(func), std::forward<ForEachFunc>(forEachFunc), std::forward<Tuple>(tuple)); } // exemplar template<typename T> struct Foo { T& data() { return _val; } T _val; }; struct Extract { template<typename T> T& operator() (Foo<T>& f) { return f.data(); } }; int main() { Foo<int> i { 5 }; Foo<double> d { 6. }; Foo<const char*> s { "hello world" }; auto cb = [](int& i, const double& d, const char* s) { std::cout << "i=" << i << ", d=" << d << ", s=" << s << std::endl; i += 2; }; // rvalue reference to tuple invokeWithMemberFromAll(cb, Extract{}, std::tie(i, d, s)); std::cout << i.data() << std::endl; // lvalue reference to tuple - fails auto tuple = std::tie(i, d, s); invokeWithMemberFromAll(cb, Extract{}, tuple); std::cout << i.data() << std::endl; }
template<typename Func, typename ForEachFunc, typename... Args> static auto apply(Func&& func, ForEachFunc&& forEachFunc, std::tuple<Args...>&& args) the 3rd argument is an rvalue tuple, not a tuple of forwarding references, or a forwarding reference to a tuple. Universal references (currently called "forwarding references" in the under development C++1z standard) usually require a deduced type. They do require that the type the && is applied to could be either a reference or a non-reference type. A std::tuple<?> is always a non-reference type, so && makes it an rvalue reference, not a forwarding reference, when placed like std::tuple<?>&&. It appears you switch from Tuple&& to std::tuple<?>&& for no reason other than to count the number of Args.... If I'm right, then std::tuple_size<std::decay_t<Tuple>>{} equals sizeof...(Args).
The problem is with your apply function - it requires an rvalue of type std::tuple<Args...>: template<typename Func, typename ForEachFunc, typename... Args> static auto apply(Func&& func, ForEachFunc&& forEachFunc, std::tuple<Args...>&& args) Here's one possible fix using std::tuple_size instead of sizeof...(Args) from your code: struct TupleForEachInvoker { template<typename Func, typename ForEachFunc, typename Tuple, size_t... Seq> static auto invoke(Func&& func, ForEachFunc&& forEachFunc, Tuple&& tuple, Sequence<Seq...>) -> decltype(func(forEachFunc(std::get<Seq>(std::forward<Tuple>(tuple)))...)) { return func(forEachFunc(std::get<Seq>(std::forward<Tuple>(tuple)))...); } template<typename Func, typename ForEachFunc, typename Tuple> static auto apply(Func&& func, ForEachFunc&& forEachFunc, Tuple&& args) -> decltype(invoke(std::forward<Func>(func), std::forward<ForEachFunc>(forEachFunc), std::forward<Tuple>(args), typename GenerateSequence<std::tuple_size<std::decay_t<Tuple>>::value>::type())) { return invoke(std::forward<Func>(func), std::forward<ForEachFunc>(forEachFunc), std::forward<Tuple>(args), typename GenerateSequence<std::tuple_size<std::decay_t<Tuple>>::value>::type()); } }; template<typename Func, typename ForEachFunc, typename Tuple> inline auto invokeWithMemberFromAll(Func&& func, ForEachFunc&& forEachFunc, Tuple&& tuple) -> decltype(TupleForEachInvoker::apply(std::forward<Func>(func), std::forward<ForEachFunc>(forEachFunc), std::forward<Tuple>(tuple))) { return TupleForEachInvoker::apply(std::forward<Func>(func), std::forward<ForEachFunc>(forEachFunc), std::forward<Tuple>(tuple)); } Live Demo
How to implement a variadic tuple_map operation?
I want to implement a function which maps a variadic list of tuples to another tuple, given a function. It applies an N-ary function f to a list of elements taken from a list of N tuples (each with size at least M) and creates a new M-element tuple from the result of these applications. For a list of N tuples, each with M elements, the call to std::make_tuple would look like this pseudocode: std::make_tuple( f(t1_1, t2_1, t3_1, ..., tN_1), f(t1_2, t2_2, t3_2, ..., tN_2), f(t1_3, t2_3, t3_3, ..., tN_3), ... f(t1_M, t2_M, t3_M, ..., tN_M) ) Sometimes this operation is named zipWith in other languages. I want this function, tuple_map, to have the following signature: template<class Tuple1, class... Tuples2, class Function> auto tuple_map(Tuple1&& tuple1, Tuples&&... tuples, Function f); I've figured out the implementation for a function taking a single tuple: #include <tuple> #include <integer_sequence> #include <type_traits> #include <utility> template<class Tuple, class Function, size_t... I> auto tuple_map_impl(Tuple&& t, Function f, std::index_sequence<I...>) -> decltype( std::make_tuple( f(std::get<I>(std::forward<Tuple>(t)))... ) ) { return std::make_tuple( f(std::get<I>(std::forward<Tuple>(t)))... ); } template<class Tuple, class Function> auto tuple_map(Tuple&& t, Function f) -> decltype( tuple_map_impl( std::forward<Tuple>(t), f, std::make_index_sequence< std::tuple_size<std::decay_t<Tuple>>::value >() ) ) { using indices = std::make_index_sequence< std::tuple_size<std::decay_t<Tuple>>::value >; return tuple_map_impl(std::forward<Tuple>(t), indices()); } When I introduce another parameter pack (Tuples) in addition to I..., it causes problems: template<class Tuple1, class... Tuples, class Function, size_t... I> auto tuple_map_impl(Tuple1&& tuple1, Tuples&&... tuples, Function f, std::index_sequence<I...>) -> decltype( std::make_tuple( f( std::get<I>(std::forward<Tuple1>(t1)), std::get<I>(std::forward<Tuples>(tuples))... )... ) ) { return std::make_tuple( f( std::get<I>(std::forward<Tuple>(t)), std::get<I>(std::forward<Tuples>(tuples))... )... ); } Compiler error: error: mismatched argument pack lengths while expanding ‘get<I>(forward<Tuples>(tuples))’ This is because I've used two packs with different lengths (I and Tuples) within the same expression. I can't think of a different way to write this function which would not use the two packs within the same expression. What is the best way to implement tuple_map?
If I understand what you're trying to do correctly, this code seems to do the trick with Visual Studio 2013 (November 2013 CTP): #include <iostream> #include <tuple> #include <utility> using namespace std; // index_sequence implementation since VS2013 doesn't have it yet template <size_t... Ints> class index_sequence { public: static size_t size() { return sizeof...(Ints); } }; template <size_t Start, typename Indices, size_t End> struct make_index_sequence_impl; template <size_t Start, size_t... Indices, size_t End> struct make_index_sequence_impl<Start, index_sequence<Indices...>, End> { typedef typename make_index_sequence_impl< Start + 1, index_sequence<Indices..., Start>, End>::type type; }; template <size_t End, size_t... Indices> struct make_index_sequence_impl<End, index_sequence<Indices...>, End> { typedef index_sequence<Indices...> type; }; template <size_t N> using make_index_sequence = typename make_index_sequence_impl<0, index_sequence<>, N>::type; // The code that actually implements tuple_map template <size_t I, typename F, typename... Tuples> auto tuple_zip_invoke(F f, const Tuples &... ts) { return f(get<I>(ts)...); } template <typename F, size_t... Is, typename... Tuples> auto tuple_map_impl(F f, index_sequence<Is...>, const Tuples &... ts) { return make_tuple(tuple_zip_invoke<Is>(f, ts...)...); } template <typename F, typename Tuple, typename... Tuples> auto tuple_map(F f, const Tuple &t, const Tuples &... ts) { return tuple_map_impl(f, make_index_sequence<tuple_size<Tuple>::value>(), t, ts...); } int sum(int a, int b, int c) { return a + b + c; } int main() { auto res = tuple_map(sum, make_tuple(1, 4), make_tuple(2, 5), make_tuple(3, 6)); cout << "(" << get<0>(res) << ", " << get<1>(res) << ")\n"; return 0; } Output is: (6, 15)
I might approach this problem by factoring the mapping and the catting. Using your existing tuple_map, try this: template <typename ...Tuple, typename F> auto tuple_map(Tuple && tuple, F f) { return std::tuple_cat(tuple_map(std::forward<Tuple>(tuple), f)...); }
You can use recursion and std::tuple_cat() like this: template <class Function, class Tuple, size_t... I> auto tuple_map_impl(Function f, Tuple&& t, std::index_sequence<I...>) { return std::make_tuple(f(std::get<I>(std::forward<Tuple>(t)))...); } template <class F, class Tuple, class... Tuples> auto tuple_map(F f, Tuple&& t, Tuples&&... tuples) { return std::tuple_cat(tuple_map_impl(f, std::forward<Tuple>(t), std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>{}), tuple_map(f, tuples...)); } template <class F> auto tuple_map(F) { return std::make_tuple(); } Live Demo
C++ weak functor with default return value
With the help of this community, I have the following template methods... // void return template<typename R, typename = typename std::enable_if<std::is_void<R>::value, R>::type, typename F, typename T, typename... A> static std::function<R()> Weak(F func, const std::shared_ptr<T>&& obj, A&&... args) { return std::bind(Wrapper<R>(), std::weak_ptr<T>(obj), std::function<R()>(std::bind(func, obj.get(), args...))); } // non void return template<typename R, R D = R(), typename = typename std::enable_if<std::is_void<R>::value == false, R>::type, typename F, typename T, typename... A> static std::function<R()> Weak(F func, const std::shared_ptr<T>&& obj, A&&... args) { return std::bind(Wrapper<R>(), std::weak_ptr<T>(obj), std::function<R()>(std::bind(func, obj.get(), args...)), D); } ...where Wrapper is a template class that tests the weak pointer and returns the specified default value if it is expired. Usage examples are... (a) Bind::Weak<void>(func, obj, args...) (b) Bind::Weak<bool>(func, obj, args...) // default bool is "false" (c) Bind::Weak<bool, true>(func, obj, args...) (b) Bind::Weak<int>(func, obj, args...) // default int is "0" (c) Bind::Weak<int, 42>(func, obj, args...) Is it be possible to support the following usage instead? (a) Bind::Weak<void>(func, obj, args...) (b) Bind::Weak<true>(func, obj, args...) (c) Bind::Weak<42>(func, obj, args...) [EDIT] The response from Oktalist below gave me the following idea... // weak from shared - void return template<typename F, typename O, typename... A> static std::function<void()> Weak(F func, const std::shared_ptr<O>&& obj, A&&... args) { return std::bind(Wrapper<void>(), std::weak_ptr<O>(obj), std::function<void()>(std::bind(func, obj.get(), std::forward<A>(args)...))); } // weak from shared - non-void return template<typename F, typename R = typename std::enable_if<std::is_void<F>::value == false, F>::type, typename O, typename... A> static std::function<R()> Weak(R&& val, F func, const std::shared_ptr<O>&& obj, A&&... args) { return std::bind(Wrapper<R>(), std::weak_ptr<O>(obj), std::function<R()>(std::bind(func, obj.get(), std::forward<A>(args)...)), val); } ...which gives this usage... (a) Bind::Weak(func, obj, args...) (b) Bind::Weak(true, func, obj, args...) (c) Bind::Weak(42, func, obj, args...)
The only way I can think of which might help you tackle this problem is to overload your non-void version of Weak for each kind of non-type template argument you might support. In your example this is a bool and an int. This is not your code as it's simplified but hopefully conveys the idea: // accepts a type. using enable_if you'd do something like this // to catch all the non-void types that don't have a default value. template <class R, ...enable_if to only deal with non-void... > R Get( R r ) { return r; } // this for if the user wants to put an actual value as a parameter // to be the default rather than just 'int' template <int R> decltype(R) Get( decltype(R) r = R ) { return r; } // ... and do the previous one for each specific type which can have a default Basically the issue is that specific values like '42' and 'false' won't bind to a 'typename'. So you need specialized templates of the function to accept these values and you can then get the type of that value when you need to using decltype(). This will remove the need for sometimes having one parameter (ie: Get< int >) and other times two (ie: Get< int, 42 > to have the default specified). Another restriction which seems acceptable for your example but is probably not acceptable in the 'real world' is limitations on the template argument itself. You won't be able to do Weak< foo > where foo is an instance of a class.
I've spent some time on the same problem and came up with this: #include <functional> #include <memory> template <typename F, typename T> struct Invoker { typedef std::weak_ptr<T> P; Invoker(F func, P ptr) : func_(func), ptr_(ptr) { } template <typename... Args> typename std::result_of<F(Args...)>::type operator()(Args&&... args) { typedef typename std::result_of<F(Args...)>::type R; if (ptr_.lock()) return func_(std::forward<Args>(args)...); return R(); } private: F func_; P ptr_; }; template <typename F, typename T, typename... Args> struct _Bind_helper { typedef Invoker<decltype( std::bind(std::declval<F>(), std::declval<Args>()...) ), T> InvokerType; }; template <typename F, typename T, typename... Args> typename _Bind_helper<F, T, Args...>::InvokerType weak_bind(std::weak_ptr<T> ptr, F func, Args&&... args) { typedef typename _Bind_helper<F, T, Args...>::InvokerType R; return R(std::bind(std::forward<F>(func), std::forward<Args>(args)...), ptr); } There are notable limitations on default result value, but it seems to work most of the time :)
Yes, you can deduce the return type of the callable type F using function traits. Remove typename R from the template parameter list, move typename F to the beginning of the template parameter list, and replace all occurrences of R with typename function_traits<F>::return_type. We can use a template using declaration to help us: template <typename F> using Ret = typename function_traits<F>::return_type; template <typename T> using EnableIfVoid = typename std::enable_if<std::is_void<T>::value, T>::type; template <typename T> using EnableIfNotVoid = typename std::enable_if<! std::is_void<T>::value, T>::type; // void return template<typename F, typename = EnableIfVoid<Ret<F>>, typename T, typename... A> static std::function<void()> Weak(F func, const std::shared_ptr<T>& obj, A&&... args) { return std::bind(Wrapper<void>(), std::weak_ptr<T>(obj), std::function<void()>(std::bind(func, obj.get(), std::forward<Args>(args)...))); } // non void return with explicit default template<typename F, typename = EnableIfNotVoid<Ret<F>>, typename T, typename... A> static std::function<Ret<F>()> Weak(Ret<F> d, F func, const std::shared_ptr<T>& obj, A&&... args) { return std::bind(Wrapper<Ret<F>>(), std::weak_ptr<T>(obj), std::function<Ret<F>()>(std::bind(func, obj.get(), std::forward<Args>(args)...)), d); } // non void return with implicit default template<typename F, typename = EnableIfNotVoid<Ret<F>>, typename T, typename... A> static std::function<Ret<F>()> Weak(F func, const std::shared_ptr<T>& obj, A&&... args) { return Weak(Ret<F>(), func, obj, std::forward<Args>(args)...); } I had to make your D parameter a function argument instead of a template parameter, otherwise you would've been forced to write Bind::Weak<decltype(f), 42>(f, obj). (a) Bind::Weak(func, obj, args...) (b) Bind::Weak(true, func, obj, args...) (c) Bind::Weak(42, func, obj, args...) [I feel you should be able to do this without having to call bind twice, but I don't know enough about what you are trying to do.]
How do I expand a tuple into variadic template function's arguments?
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?
In C++17 you can do this: std::apply(the_function, the_tuple); 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: #include <tuple> template <typename T, typename U> void my_func(T &&t, U &&u) {} int main(int argc, char *argv[argc]) { std::tuple<int, float> my_tuple; std::apply([](auto &&... args) { my_func(args...); }, my_tuple); return 0; } 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/.
Here's my code if anyone is interested Basically at compile time the compiler will recursively unroll all arguments in various inclusive function calls <N> -> calls <N-1> -> calls ... -> calls <0> which is the last one and the compiler will optimize away the various intermediate function calls to only keep the last one which is the equivalent of func(arg1, arg2, arg3, ...) Provided are 2 versions, one for a function called on an object and the other for a static function. #include <tr1/tuple> /** * Object Function Tuple Argument Unpacking * * This recursive template unpacks the tuple parameters into * variadic template arguments until we reach the count of 0 where the function * is called with the correct parameters * * #tparam N Number of tuple arguments to unroll * * #ingroup g_util_tuple */ template < uint N > struct apply_obj_func { template < typename T, typename... ArgsF, typename... ArgsT, typename... Args > static void applyTuple( T* pObj, void (T::*f)( ArgsF... ), const std::tr1::tuple<ArgsT...>& t, Args... args ) { apply_obj_func<N-1>::applyTuple( pObj, f, t, std::tr1::get<N-1>( t ), args... ); } }; //----------------------------------------------------------------------------- /** * Object Function Tuple Argument Unpacking End Point * * This recursive template unpacks the tuple parameters into * variadic template arguments until we reach the count of 0 where the function * is called with the correct parameters * * #ingroup g_util_tuple */ template <> struct apply_obj_func<0> { template < typename T, typename... ArgsF, typename... ArgsT, typename... Args > static void applyTuple( T* pObj, void (T::*f)( ArgsF... ), const std::tr1::tuple<ArgsT...>& /* t */, Args... args ) { (pObj->*f)( args... ); } }; //----------------------------------------------------------------------------- /** * Object Function Call Forwarding Using Tuple Pack Parameters */ // Actual apply function template < typename T, typename... ArgsF, typename... ArgsT > void applyTuple( T* pObj, void (T::*f)( ArgsF... ), std::tr1::tuple<ArgsT...> const& t ) { apply_obj_func<sizeof...(ArgsT)>::applyTuple( pObj, f, t ); } //----------------------------------------------------------------------------- /** * Static Function Tuple Argument Unpacking * * This recursive template unpacks the tuple parameters into * variadic template arguments until we reach the count of 0 where the function * is called with the correct parameters * * #tparam N Number of tuple arguments to unroll * * #ingroup g_util_tuple */ template < uint N > struct apply_func { template < typename... ArgsF, typename... ArgsT, typename... Args > static void applyTuple( void (*f)( ArgsF... ), const std::tr1::tuple<ArgsT...>& t, Args... args ) { apply_func<N-1>::applyTuple( f, t, std::tr1::get<N-1>( t ), args... ); } }; //----------------------------------------------------------------------------- /** * Static Function Tuple Argument Unpacking End Point * * This recursive template unpacks the tuple parameters into * variadic template arguments until we reach the count of 0 where the function * is called with the correct parameters * * #ingroup g_util_tuple */ template <> struct apply_func<0> { template < typename... ArgsF, typename... ArgsT, typename... Args > static void applyTuple( void (*f)( ArgsF... ), const std::tr1::tuple<ArgsT...>& /* t */, Args... args ) { f( args... ); } }; //----------------------------------------------------------------------------- /** * Static Function Call Forwarding Using Tuple Pack Parameters */ // Actual apply function template < typename... ArgsF, typename... ArgsT > void applyTuple( void (*f)(ArgsF...), std::tr1::tuple<ArgsT...> const& t ) { apply_func<sizeof...(ArgsT)>::applyTuple( f, t ); } // *************************************** // Usage // *************************************** template < typename T, typename... Args > class Message : public IMessage { typedef void (T::*F)( Args... args ); public: Message( const std::string& name, T& obj, F pFunc, Args... args ); private: virtual void doDispatch( ); T* pObj_; F pFunc_; std::tr1::tuple<Args...> args_; }; //----------------------------------------------------------------------------- template < typename T, typename... Args > Message<T, Args...>::Message( const std::string& name, T& obj, F pFunc, Args... args ) : IMessage( name ), pObj_( &obj ), pFunc_( pFunc ), args_( std::forward<Args>(args)... ) { } //----------------------------------------------------------------------------- template < typename T, typename... Args > void Message<T, Args...>::doDispatch( ) { try { applyTuple( pObj_, pFunc_, args_ ); } catch ( std::exception& e ) { } }
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: // ------------- UTILITY--------------- template<int...> struct index_tuple{}; template<int I, typename IndexTuple, typename... Types> struct make_indexes_impl; template<int I, int... Indexes, typename T, typename ... Types> struct make_indexes_impl<I, index_tuple<Indexes...>, T, Types...> { typedef typename make_indexes_impl<I + 1, index_tuple<Indexes..., I>, Types...>::type type; }; template<int I, int... Indexes> struct make_indexes_impl<I, index_tuple<Indexes...> > { typedef index_tuple<Indexes...> type; }; template<typename ... Types> struct make_indexes : make_indexes_impl<0, index_tuple<>, Types...> {}; Now the code which does the job is not that big: // ----------UNPACK TUPLE AND APPLY TO FUNCTION --------- #include <tuple> #include <iostream> using namespace std; template<class Ret, class... Args, int... Indexes > Ret apply_helper( Ret (*pf)(Args...), index_tuple< Indexes... >, tuple<Args...>&& tup) { return pf( forward<Args>( get<Indexes>(tup))... ); } template<class Ret, class ... Args> Ret apply(Ret (*pf)(Args...), const tuple<Args...>& tup) { return apply_helper(pf, typename make_indexes<Args...>::type(), tuple<Args...>(tup)); } template<class Ret, class ... Args> Ret apply(Ret (*pf)(Args...), tuple<Args...>&& tup) { return apply_helper(pf, typename make_indexes<Args...>::type(), forward<tuple<Args...>>(tup)); } Test is shown bellow: // --------------------- TEST ------------------ void one(int i, double d) { std::cout << "function one(" << i << ", " << d << ");\n"; } int two(int i) { std::cout << "function two(" << i << ");\n"; return i; } int main() { std::tuple<int, double> tup(23, 4.5); apply(one, tup); int d = apply(two, std::make_tuple(2)); return 0; } 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...
I find this to be the most elegant solution (and it is optimally forwarded): #include <cstddef> #include <tuple> #include <type_traits> #include <utility> template<size_t N> struct Apply { template<typename F, typename T, typename... A> static inline auto apply(F && f, T && t, A &&... a) -> decltype(Apply<N-1>::apply( ::std::forward<F>(f), ::std::forward<T>(t), ::std::get<N-1>(::std::forward<T>(t)), ::std::forward<A>(a)... )) { return Apply<N-1>::apply(::std::forward<F>(f), ::std::forward<T>(t), ::std::get<N-1>(::std::forward<T>(t)), ::std::forward<A>(a)... ); } }; template<> struct Apply<0> { template<typename F, typename T, typename... A> static inline auto apply(F && f, T &&, A &&... a) -> decltype(::std::forward<F>(f)(::std::forward<A>(a)...)) { return ::std::forward<F>(f)(::std::forward<A>(a)...); } }; template<typename F, typename T> inline auto apply(F && f, T && t) -> decltype(Apply< ::std::tuple_size< typename ::std::decay<T>::type >::value>::apply(::std::forward<F>(f), ::std::forward<T>(t))) { return Apply< ::std::tuple_size< typename ::std::decay<T>::type >::value>::apply(::std::forward<F>(f), ::std::forward<T>(t)); } Example usage: void foo(int i, bool b); std::tuple<int, bool> t = make_tuple(20, false); void m() { apply(&foo, t); } 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): #include <cstddef> #include <tuple> #include <type_traits> #include <utility> template<size_t N> struct Apply { template<typename F, typename T, typename... A> static inline auto apply(F && f, T && t, A &&... a) { return Apply<N-1>::apply(::std::forward<F>(f), ::std::forward<T>(t), ::std::get<N-1>(::std::forward<T>(t)), ::std::forward<A>(a)... ); } }; template<> struct Apply<0> { template<typename F, typename T, typename... A> static inline auto apply(F && f, T &&, A &&... a) { return ::std::forward<F>(f)(::std::forward<A>(a)...); } }; template<typename F, typename T> inline auto apply(F && f, T && t) { return Apply< ::std::tuple_size< ::std::decay_t<T> >::value>::apply(::std::forward<F>(f), ::std::forward<T>(t)); } Here is a version for member functions (not tested very much!): using std::forward; // You can change this if you like unreadable code or care hugely about namespace pollution. template<size_t N> struct ApplyMember { template<typename C, typename F, typename T, typename... A> static inline auto apply(C&& c, F&& f, T&& t, A&&... a) -> decltype(ApplyMember<N-1>::apply(forward<C>(c), forward<F>(f), forward<T>(t), std::get<N-1>(forward<T>(t)), forward<A>(a)...)) { return ApplyMember<N-1>::apply(forward<C>(c), forward<F>(f), forward<T>(t), std::get<N-1>(forward<T>(t)), forward<A>(a)...); } }; template<> struct ApplyMember<0> { template<typename C, typename F, typename T, typename... A> static inline auto apply(C&& c, F&& f, T&&, A&&... a) -> decltype((forward<C>(c)->*forward<F>(f))(forward<A>(a)...)) { return (forward<C>(c)->*forward<F>(f))(forward<A>(a)...); } }; // C is the class, F is the member function, T is the tuple. template<typename C, typename F, typename T> inline auto apply(C&& c, F&& f, T&& t) -> decltype(ApplyMember<std::tuple_size<typename std::decay<T>::type>::value>::apply(forward<C>(c), forward<F>(f), forward<T>(t))) { return ApplyMember<std::tuple_size<typename std::decay<T>::type>::value>::apply(forward<C>(c), forward<F>(f), forward<T>(t)); } // Example: class MyClass { public: void foo(int i, bool b); }; MyClass mc; std::tuple<int, bool> t = make_tuple(20, false); void m() { apply(&mc, &MyClass::foo, t); }
template<typename F, typename Tuple, std::size_t ... I> auto apply_impl(F&& f, Tuple&& t, std::index_sequence<I...>) { return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...); } template<typename F, typename Tuple> auto apply(F&& f, Tuple&& t) { using Indices = std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>; return apply_impl(std::forward<F>(f), std::forward<Tuple>(t), Indices()); } This is adapted from the C++14 draft using index_sequence. I might propose to have apply in a future standard (TS).
All this implementations are good. But due to use of pointer to member function compiler often cannot inline the target function call (at least gcc 4.8 can't, no matter what Why gcc can't inline function pointers that can be determined?) But things changes if send pointer to member function as template arguments, not as function params: /// from https://stackoverflow.com/a/9288547/1559666 template<int ...> struct seq {}; template<int N, int ...S> struct gens : gens<N-1, N-1, S...> {}; template<int ...S> struct gens<0, S...>{ typedef seq<S...> type; }; template<typename TT> using makeSeq = typename gens< std::tuple_size< typename std::decay<TT>::type >::value >::type; // deduce function return type template<class ...Args> struct fn_type; template<class ...Args> struct fn_type< std::tuple<Args...> >{ // will not be called template<class Self, class Fn> static auto type_helper(Self &self, Fn f) -> decltype((self.*f)(declval<Args>()...)){ //return (self.*f)(Args()...); return NULL; } }; template<class Self, class ...Args> struct APPLY_TUPLE{}; template<class Self, class ...Args> struct APPLY_TUPLE<Self, std::tuple<Args...>>{ Self &self; APPLY_TUPLE(Self &self): self(self){} template<class T, T (Self::* f)(Args...), class Tuple> void delayed_call(Tuple &&list){ caller<T, f, Tuple >(forward<Tuple>(list), makeSeq<Tuple>() ); } template<class T, T (Self::* f)(Args...), class Tuple, int ...S> void caller(Tuple &&list, const seq<S...>){ (self.*f)( std::get<S>(forward<Tuple>(list))... ); } }; #define type_of(val) typename decay<decltype(val)>::type #define apply_tuple(obj, fname, tuple) \ APPLY_TUPLE<typename decay<decltype(obj)>::type, typename decay<decltype(tuple)>::type >(obj).delayed_call< \ decltype( fn_type< type_of(tuple) >::type_helper(obj, &decay<decltype(obj)>::type::fname) ), \ &decay<decltype(obj)>::type::fname \ > \ (tuple); And ussage: struct DelayedCall { void call_me(int a, int b, int c){ std::cout << a+b+c; } void fire(){ tuple<int,int,int> list = make_tuple(1,2,3); apply_tuple(*this, call_me, list); // even simpler than previous implementations } }; Proof of inlinable http://goo.gl/5UqVnC With small changes, we can "overload" apply_tuple: #define VA_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N #define VA_NARGS(...) VA_NARGS_IMPL(X,##__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0) #define VARARG_IMPL_(base, count, ...) base##count(__VA_ARGS__) #define VARARG_IMPL(base, count, ...) VARARG_IMPL_(base, count, __VA_ARGS__) #define VARARG(base, ...) VARARG_IMPL(base, VA_NARGS(__VA_ARGS__), __VA_ARGS__) #define apply_tuple2(fname, tuple) apply_tuple3(*this, fname, tuple) #define apply_tuple3(obj, fname, tuple) \ APPLY_TUPLE<typename decay<decltype(obj)>::type, typename decay<decltype(tuple)>::type >(obj).delayed_call< \ decltype( fn_type< type_of(tuple) >::type_helper(obj, &decay<decltype(obj)>::type::fname) ), \ &decay<decltype(obj)>::type::fname \ /* ,decltype(tuple) */> \ (tuple); #define apply_tuple(...) VARARG(apply_tuple, __VA_ARGS__) ... apply_tuple(obj, call_me, list); apply_tuple(call_me, list); // call this->call_me(list....) Plus this is the only one solution which works with templated functions.
1) if you have a readymade parameter_pack structure as function argument, you can just use std::tie like this: template <class... Args> void tie_func(std::tuple<Args...> t, Args&... args) { std::tie<Args...>(args...) = t; } int main() { std::tuple<int, double, std::string> t(2, 3.3, "abc"); int i; double d; std::string s; tie_func(t, i, d, s); std::cout << i << " " << d << " " << s << std::endl; } 2) if you don't have a readymade parampack arg, you'll have to unwind the tuple like this #include <tuple> #include <functional> #include <iostream> template<int N> struct apply_wrap { template<typename R, typename... TupleArgs, typename... UnpackedArgs> static R applyTuple( std::function<R(TupleArgs...)>& f, const std::tuple<TupleArgs...>& t, UnpackedArgs... args ) { return apply_wrap<N-1>::applyTuple( f, t, std::get<N-1>( t ), args... ); } }; template<> struct apply_wrap<0> { template<typename R, typename... TupleArgs, typename... UnpackedArgs> static R applyTuple( std::function<R(TupleArgs...)>& f, const std::tuple<TupleArgs...>&, UnpackedArgs... args ) { return f( args... ); } }; template<typename R, typename... TupleArgs> R applyTuple( std::function<R(TupleArgs...)>& f, std::tuple<TupleArgs...> const& t ) { return apply_wrap<sizeof...(TupleArgs)>::applyTuple( f, t ); } int fac(int n) { int r=1; for(int i=2; i<=n; ++i) r *= i; return r; } int main() { auto t = std::make_tuple(5); auto f = std::function<decltype(fac)>(&fac); cout << applyTuple(f, t); }
The news does not look good. Having read over the just-released draft standard, I'm not seeing a built-in solution to this, which does seem odd. The best place to ask about such things (if you haven't already) is comp.lang.c++.moderated, because some folks involved in drafting the standard post there regularly. If you check out this thread, someone has the same question (maybe it's you, in which case you're going to find this whole answer a little frustrating!), and a few butt-ugly implementations are suggested. I just wondered if it would be simpler to make the function accept a tuple, as the conversion that way is easier. But this implies that all functions should accept tuples as arguments, for maximum flexibility, and so that just demonstrates the strangeness of not providing a built-in expansion of tuple to function argument pack. Update: the link above doesn't work - try pasting this: http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/750fa3815cdaac45/d8dc09e34bbb9661?lnk=gst&q=tuple+variadic#d8dc09e34bbb9661
How about this: // Warning: NOT tested! #include <cstddef> #include <tuple> #include <type_traits> #include <utility> using std::declval; using std::forward; using std::get; using std::integral_constant; using std::size_t; using std::tuple; namespace detail { template < typename Func, typename ...T, typename ...Args > auto explode_tuple( integral_constant<size_t, 0u>, tuple<T...> const &t, Func &&f, Args &&...a ) -> decltype( forward<Func>(f)(declval<T const>()...) ) { return forward<Func>( f )( forward<Args>(a)... ); } template < size_t Index, typename Func, typename ...T, typename ...Args > auto explode_tuple( integral_constant<size_t, Index>, tuple<T...> const&t, Func &&f, Args &&...a ) -> decltype( forward<Func>(f)(declval<T const>()...) ) { return explode_tuple( integral_constant<size_t, Index - 1u>{}, t, forward<Func>(f), get<Index - 1u>(t), forward<Args>(a)... ); } } template < typename Func, typename ...T > auto run_tuple( Func &&f, tuple<T...> const &t ) -> decltype( forward<Func>(f)(declval<T const>()...) ) { return detail::explode_tuple( integral_constant<size_t, sizeof...(T)>{}, t, forward<Func>(f) ); } template < typename Tret, typename ...T > Tret func_T( tuple<T...> const &t ) { return run_tuple( &func<Tret, T...>, t ); } The run_tuple function template takes the given tuple and pass its elements individually to the given function. It carries out its work by recursively calling its helper function templates explode_tuple. It's important that run_tuple passes the tuple's size to explode_tuple; that number acts as a counter for how many elements to extract. If the tuple is empty, then run_tuple calls the first version of explode_tuple with the remote function as the only other argument. The remote function is called with no arguments and we're done. If the tuple is not empty, a higher number is passed to the second version of explode_tuple, along with the remote function. A recursive call to explode_tuple is made, with the same arguments, except the counter number is decreased by one and (a reference to) the last tuple element is tacked on as an argument after the remote function. In a recursive call, either the counter isn't zero, and another call is made with the counter decreased again and the next-unreferenced element is inserted in the argument list after the remote function but before the other inserted arguments, or the counter reaches zero and the remote function is called with all the arguments accumulated after it. I'm not sure I have the syntax of forcing a particular version of a function template right. I think you can use a pointer-to-function as a function object; the compiler will automatically fix it.
I am evaluating MSVS 2013RC, and it failed to compile some of the previous solutions proposed here in some cases. For example, MSVS will fail to compile "auto" returns if there are too many function parameters, because of a namespace imbrication limit (I sent that info to Microsoft to have it corrected). In other cases, we need access to the function's return, although that can also be done with a lamda: the following two examples give the same result.. apply_tuple([&ret1](double a){ret1 = cos(a); }, std::make_tuple<double>(.2)); ret2 = apply_tuple((double(*)(double))cos, std::make_tuple<double>(.2)); And thanks again to those who posted answers here before me, I wouldn't have gotten to this without it... so here it is: template<size_t N> struct apply_impl { template<typename F, typename T, typename... A> static inline auto apply_tuple(F&& f, T&& t, A&&... a) -> decltype(apply_impl<N-1>::apply_tuple(std::forward<F>(f), std::forward<T>(t), std::get<N-1>(std::forward<T>(t)), std::forward<A>(a)...)) { return apply_impl<N-1>::apply_tuple(std::forward<F>(f), std::forward<T>(t), std::get<N-1>(std::forward<T>(t)), std::forward<A>(a)...); } template<typename C, typename F, typename T, typename... A> static inline auto apply_tuple(C*const o, F&& f, T&& t, A&&... a) -> decltype(apply_impl<N-1>::apply_tuple(o, std::forward<F>(f), std::forward<T>(t), std::get<N-1>(std::forward<T>(t)), std::forward<A>(a)...)) { return apply_impl<N-1>::apply_tuple(o, std::forward<F>(f), std::forward<T>(t), std::get<N-1>(std::forward<T>(t)), std::forward<A>(a)...); } }; // This is a work-around for MSVS 2013RC that is required in some cases #if _MSC_VER <= 1800 /* update this when bug is corrected */ template<> struct apply_impl<6> { template<typename F, typename T, typename... A> static inline auto apply_tuple(F&& f, T&& t, A&&... a) -> decltype(std::forward<F>(f)(std::get<0>(std::forward<T>(t)), std::get<1>(std::forward<T>(t)), std::get<2>(std::forward<T>(t)), std::get<3>(std::forward<T>(t)), std::get<4>(std::forward<T>(t)), std::get<5>(std::forward<T>(t)), std::forward<A>(a)...)) { return std::forward<F>(f)(std::get<0>(std::forward<T>(t)), std::get<1>(std::forward<T>(t)), std::get<2>(std::forward<T>(t)), std::get<3>(std::forward<T>(t)), std::get<4>(std::forward<T>(t)), std::get<5>(std::forward<T>(t)), std::forward<A>(a)...); } template<typename C, typename F, typename T, typename... A> static inline auto apply_tuple(C*const o, F&& f, T&& t, A&&... a) -> decltype((o->*std::forward<F>(f))(std::get<0>(std::forward<T>(t)), std::get<1>(std::forward<T>(t)), std::get<2>(std::forward<T>(t)), std::get<3>(std::forward<T>(t)), std::get<4>(std::forward<T>(t)), std::get<5>(std::forward<T>(t)), std::forward<A>(a)...)) { return (o->*std::forward<F>(f))(std::get<0>(std::forward<T>(t)), std::get<1>(std::forward<T>(t)), std::get<2>(std::forward<T>(t)), std::get<3>(std::forward<T>(t)), std::get<4>(std::forward<T>(t)), std::get<5>(std::forward<T>(t)), std::forward<A>(a)...); } }; #endif template<> struct apply_impl<0> { template<typename F, typename T, typename... A> static inline auto apply_tuple(F&& f, T&&, A&&... a) -> decltype(std::forward<F>(f)(std::forward<A>(a)...)) { return std::forward<F>(f)(std::forward<A>(a)...); } template<typename C, typename F, typename T, typename... A> static inline auto apply_tuple(C*const o, F&& f, T&&, A&&... a) -> decltype((o->*std::forward<F>(f))(std::forward<A>(a)...)) { return (o->*std::forward<F>(f))(std::forward<A>(a)...); } }; // Apply tuple parameters on a non-member or static-member function by perfect forwarding template<typename F, typename T> inline auto apply_tuple(F&& f, T&& t) -> decltype(apply_impl<std::tuple_size<typename std::decay<T>::type>::value>::apply_tuple(std::forward<F>(f), std::forward<T>(t))) { return apply_impl<std::tuple_size<typename std::decay<T>::type>::value>::apply_tuple(std::forward<F>(f), std::forward<T>(t)); } // Apply tuple parameters on a member function template<typename C, typename F, typename T> inline auto apply_tuple(C*const o, F&& f, T&& t) -> decltype(apply_impl<std::tuple_size<typename std::decay<T>::type>::value>::apply_tuple(o, std::forward<F>(f), std::forward<T>(t))) { return apply_impl<std::tuple_size<typename std::decay<T>::type>::value>::apply_tuple(o, std::forward<F>(f), std::forward<T>(t)); }
Extending on #David's solution, you can write a recursive template that Doesn't use the (overly-verbose, imo) integer_sequence semantics Doesn't use an extra temporary template parameter int N to count recursive iterations (Optional for static/global functors) uses the functor as a template parameter for compile-time optimizaion E.g.: template <class F, F func> struct static_functor { template <class... T, class... Args_tmp> static inline auto apply(const std::tuple<T...>& t, Args_tmp... args) -> decltype(func(std::declval<T>()...)) { return static_functor<F,func>::apply(t, args..., std::get<sizeof...(Args_tmp)>(t)); } template <class... T> static inline auto apply(const std::tuple<T...>& t, T... args) -> decltype(func(args...)) { return func(args...); } }; static_functor<decltype(&myFunc), &myFunc>::apply(my_tuple); 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: template <class F, class... T, class... Args_tmp> inline auto apply_functor(F&& func, const std::tuple<T...>& t, Args_tmp... args) -> decltype(func(std::declval<T>()...)) { return apply_functor(func, t, args..., std::get<sizeof...(Args_tmp)>(t)); } template <class F, class... T> inline auto apply_functor(F&& func, const std::tuple<T...>& t, T... args) -> decltype(func(args...)) { return func(args...); } apply_functor(&myFunc, my_tuple); 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 tuple t with types T..., and a parameter pack args of types Args_tmp.... When called, it recursively adds the objects from t 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 pack args. Thus, once args in the first function is completely filled with the values from t, it's type will be T... (in psuedo-code, typeid(T...) == typeid(Args_tmp...)), and thus the compiler will instead call the second overloaded function, which in turn calls func(args...). The code in the static functor example works identically, with the functor instead used as a class template argument.
Why not just wrap your variadic arguments into a tuple class and then use compile time recursion (see link) to retrieve the index you are interested in. I find that unpacking variadic templates into a container or collection may not be type safe w.r.t. heterogeneous types template<typename... Args> auto get_args_as_tuple(Args... args) -> std::tuple<Args...> { return std::make_tuple(args); }
This simple solution works for me: template<typename... T> void unwrap_tuple(std::tuple<T...>* tp) { std::cout << "And here I have the tuple types, all " << sizeof...(T) << " of them" << std::endl; } int main() { using TupleType = std::tuple<int, float, std::string, void*>; unwrap_tuple((TupleType*)nullptr); // trick compiler into using template param deduction }