如何将元组展开成可变参数模板函数的参数?

考虑使用可变参数模板参数的模板函数的情况:

template<typename Tret, typename... T> Tret func(const T&... t); 

现在,我有一个值元组。 如何使用元组值作为参数调用func() ? 我已经阅读了有关bind()函数对象, call()函数,还有apply()函数在不同的一些现在已经过时的文档。 GNU GCC 4.4的实现似乎在bind()类中有一个call()函数,但是关于这个主题的文档很less。

有人提出手写recursion攻击,但可变参数模板参数的真正价值是能够在上面的情况下使用它们。

有没有人有一个解决scheme,或暗示在哪里阅读?

这是我的代码,如果有人感兴趣

基本上在编译时,编译器将以recursion方式展开各种包含的函数调用中的所有参数<N> – >调用<N-1> – >调用… – >调用<0>这是最后一个,编译器将优化各种中间函数调用只保留最后一个相当于func(arg1,arg2,arg3,…)

提供了2个版本,一个用于在对象上调用的函数,另一个用于静态函数。

 #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 ) { } } 

在C ++中,扩展/解包元组有很多种方法,并将这些元组元素应用到可变模板函数中。 这是一个创build索引数组的小型助手类。 它在模板元编程中使用很多:

 // ------------- 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...> {}; 

现在做这个工作的代码并不是那么大:

  // ----------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)); } 

testing如下所示:

 // --------------------- 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; } 

我不是其他语言的专家,但是我想如果这些语言在他们的菜单中没有这样的function,就没有办法做到这一点。 至less用C ++你可以,而且我认为它不是那么复杂…

我觉得这是最优雅的解决scheme(最佳转发):

 #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)); } 

用法示例:

 void foo(int i, bool b); std::tuple<int, bool> t = make_tuple(20, false); void m() { apply(&foo, t); } 

不幸的是,GCC(至less4.6)没有用“抱歉,未实现:mangling超载”(这仅仅意味着编译器还没有完全实现C ++ 11规范)编译,而且由于它使用可变参数模板,在MSVC中工作,所以它或多或less是无用的。 但是,一旦有支持该规范的编译器,这将是最好的方法恕我直言。 (注意:修改这个并不难,所以你可以解决GCC的缺陷,或者用Boost预处理器来实现它,但是它破坏了优雅,所以这是我发布的版本。)

GCC 4.7现在支持这个代码就好了。

编辑:添加转发实际的函数调用,以支持右值参考forms*这在万一你正在使用clang(或者如果有人真的得到周围添加它)。

编辑:添加在非成员应用函数的正文中的函数对象周围缺less。 感谢pheedbaq指出它缺失。

编辑:这是C + + 14版本,因为它是更好(实际上还没有编译):

 #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)); } 

这里是成员函数的一个版本(没有太多testing!):

 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()); } 

这是使用index_sequence从C ++ 14草案改编而来的。 我可能会build议申请未来的标准(TS)。

在C ++ 17中,你可以这样做:

 std::apply(the_function, the_tuple); 

这已经在Clang ++ 3.9中起作用,使用std :: experimental :: apply。

这消息不好看。

读过刚刚发布的标准草案 ,我没有看到一个内置的解决scheme,这似乎很奇怪。

问这个问题的最好的地方(如果你还没有的话)是comp.lang.c ++。主持,因为有些人经常参与起草标准的post。

如果你看看这个线程 ,有人有同样的问题(也许是你,在这种情况下,你会发现这个整体的答案有点令人沮丧!),并提出了一些拙劣的实现。

我只是想知道让函数接受一个tuple是否更简单,因为这种转换更容易。 但是这意味着所有的函数都应该接受元组作为参数,以获得最大的灵活性,这样就certificate了不提供元组的内置扩展的奇怪function。

更新:上面的链接不起作用 – 尝试粘贴:

http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/750fa3815cdaac45/d8dc09e34bbb9661?lnk=gst&q=tuple+variadic#d8dc09e34bbb9661

所有这些实现都很好。 但是由于使用了成员函数编译器的指针往往不能内联目标函数调用(至lessgcc 4.8不能,不pipe为什么gcc不能内联函数指针可以确定吗? )

但是如果发送指向成员函数的指针作为模板参数,事情就会改变,而不是函数参数:

 /// 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); 

和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 } }; 

可接受的http://goo.gl/5UqVnC的certificate


随着小的变化,我们可以“超载” 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....) 

此外,这是唯一一个与模板化函数一起工作的解决scheme。

1)如果你有一个现成的parameter_pack结构作为函数参数,你可以像这样使用std :: tie:

 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)如果你没有现成的parampack arg,你必须像这样展开元组

 #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); } 

这个怎么样:

 // 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 ); } 

run_tuple函数模板获取给定的元组,并将其元素分别传递给给定的函数。 它通过recursion调用helper函数模板explode_tuple执行它的工作。 run_tuple将元组的大小传递给explode_tuple是很重要的。 这个数字就是要提取多less元素的计数器。

如果元组为空,那么run_tuple将远程函数的第一个版本explode_tuple作为唯一的其他参数。 远程函数被调用没有参数,我们完成了。 如果元组不为空,则将较高的数字与远程函数一起传递给explode_tuple的第二个版本。 对explode_tuple进行recursion调用,使用相同的参数,除了在远程函数之后将计数器编号减1和(引用)最后一个元组元素作为参数。 在recursion调用中,计数器不为零,再次调用计数器,下一个未被引用的元素被插入到远程函数之后的参数列表中,但在其他插入的参数之前,或者计数器到达零和远程函数被调用与所有参数之后积累。

我不知道我有强制function模板的特定版本的语法正确。 我认为你可以使用指针函数作为函数对象; 编译器会自动修复它。

我正在评估MSVS 2013RC,在某些情况下,它没有编译一些以前提出的解决scheme。 例如,如果由于名称空间重叠限制(我将该信息发送给Microsoft以纠正错误),MSVS将无法编译“自动”返回,如果有太多的函数参数。 在其他情况下,我们需要访问函数的返回值,虽然这也可以用lamda完成:以下两个示例给出了相同的结果。

 apply_tuple([&ret1](double a){ret1 = cos(a); }, std::make_tuple<double>(.2)); ret2 = apply_tuple((double(*)(double))cos, std::make_tuple<double>(.2)); 

再次感谢那些在我面前贴出答案的人,如果没有这个答案,我就不会得到这个答案……所以这里是:

 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)); } 

扩展@ David的解决scheme,你可以写一个recursion模板

  1. 不使用(overly-verbose,imo) integer_sequence语义
  2. 不要使用额外的临时模板参数int N来计算recursion迭代
  3. (对于静态/全局仿函数可选)使用仿函数作为编译时优化的模板参数

例如:

 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); 

另外,如果你的函子没有在编译时定义(例如,非constexpr函子实例或lambdaexpression式),你可以使用它作为函数参数而不是类模板参数,实际上完全删除包含的类:

 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); 

对于指向成员函数的可调用函数,您可以像在@David的答案中一样调整上述任一代码片段。

说明

在第二段代码中,有两个模板函数:第一个是函数func ,第二个是types为T...的tuple,第二个是参数包args ,types为Args_tmp... 当被调用时,它将从t开始( 0 )到结束递增地将t的对象添加到参数包中,然后用新递增的参数包再次调用该函数。

第二个函数的签名与第一个函数的签名几乎相同,只是它使用T...types作为参数pack args 。 因此,一旦在第一个函数中的参数完全填充了来自t的值,它的types将是T... (在伪代码中, typeid(T...) == typeid(Args_tmp...) )和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 wrt 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 }