所有这些实现都很好。但是由于使用成员函数指针,编译器通常无法内联目标函数调用(至少gcc 4.8无法,无论
为什么gcc无法内联可以确定的函数指针?怎样)。
但是如果将成员函数指针作为模板参数发送,情况就会改变:
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;
template<class ...Args>
struct fn_type;
template<class ...Args>
struct fn_type< std::tuple<Args...> >{
template<class Self, class Fn>
static auto type_helper(Self &self, Fn f) -> decltype((self.*f)(declval<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);
"使用方法:"
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);
}
};
可内联的证明
http://goo.gl/5UqVnC
通过一些小的改变,我们可以“过载”
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....)
此外,这是唯一一个与模板函数兼容的解决方案。
integer_sequence
在一个可变参数的情况下对元组进行解包,详见http://en.cppreference.com/w/cpp/utility/integer_sequence。 - Skeeninteger_sequence S
的序列,你只需调用函数func(std::get<S>(tuple)...)
,让编译器处理剩下的部分。 - Skeen