Consider the case of a templated function with variadic template arguments:
template Tret func(const T&... t);
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 struct seq {};
template struct gens : gens {};
template struct gens<0, S...>{ typedef seq type; };
template
using makeSeq = typename gens< std::tuple_size< typename std::decay::type >::value >::type;
// deduce function return type
template
struct fn_type;
template
struct fn_type< std::tuple >{
// will not be called
template
static auto type_helper(Self &self, Fn f) -> decltype((self.*f)(declval()...)){
//return (self.*f)(Args()...);
return NULL;
}
};
template
struct APPLY_TUPLE{};
template
struct APPLY_TUPLE>{
Self &self;
APPLY_TUPLE(Self &self): self(self){}
template
void delayed_call(Tuple &&list){
caller(forward(list), makeSeq() );
}
template
void caller(Tuple &&list, const seq){
(self.*f)( std::get(forward(list))... );
}
};
#define type_of(val) typename decay::type
#define apply_tuple(obj, fname, tuple) \
APPLY_TUPLE::type, typename decay::type >(obj).delayed_call< \
decltype( fn_type< type_of(tuple) >::type_helper(obj, &decay::type::fname) ), \
&decay::type::fname \
> \
(tuple);
And ussage:
struct DelayedCall
{
void call_me(int a, int b, int c){
std::cout << a+b+c;
}
void fire(){
tuple 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::type, typename decay::type >(obj).delayed_call< \
decltype( fn_type< type_of(tuple) >::type_helper(obj, &decay::type::fname) ), \
&decay::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.