Как я могу расширить кортеж в аргументы функции вариационной матрицы?

Рассмотрим случай шаблонной функции с переменными аргументами шаблона:

template Tret func(const T&... t); 

Теперь у меня есть набор значений. Как мне вызвать func() используя значения кортежа в качестве аргументов? Я прочитал о объекте функции bind() , с функцией call() , а также функции apply() в разных некоторых устаревших документах. По-видимому, реализация GNU GCC 4.4 имеет функцию call() в classе bind() , но документации по этому вопросу очень мало.

Некоторые люди предлагают ручные рекурсивные хаки, но истинная ценность вариационных аргументов шаблона заключается в том, чтобы использовать их в таких случаях, как описано выше.

У кого-нибудь есть решение, или намек на то, где читать об этом?

Вот мой код, если кто-то заинтересован

В основном во время компиляции компилятор рекурсивно разворачивает все аргументы в различных включенных вызовах функций -> вызывает -> вызывает … -> вызывает <0>, который является последним, и компилятор будет оптимизирован различные промежуточные функции вызывают только сохранение последнего, что является эквивалентом func (arg1, arg2, arg3, …)

Предусмотрены 2 версии: одна для функции, называемой объектом, а другая для статической функции.

 #include  /** * 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& t, Args... args ) { apply_obj_func::applyTuple( pObj, f, t, std::tr1::get( 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& /* 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 const& t ) { apply_obj_func::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& t, Args... args ) { apply_func::applyTuple( f, t, std::tr1::get( 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& /* 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 const& t ) { apply_func::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_; }; //----------------------------------------------------------------------------- template < typename T, typename... Args > Message::Message( const std::string& name, T& obj, F pFunc, Args... args ) : IMessage( name ), pObj_( &obj ), pFunc_( pFunc ), args_( std::forward(args)... ) { } //----------------------------------------------------------------------------- template < typename T, typename... Args > void Message::doDispatch( ) { try { applyTuple( pObj_, pFunc_, args_ ); } catch ( std::exception& e ) { } } 

В C ++ существует множество способов расширения / распаковки кортежа и применения этих элементов кортежа к переменной функции шаблона. Вот небольшой вспомогательный class, который создает индексный массив. Он много используется в метапрограммировании шаблонов:

 // ------------- UTILITY--------------- template struct index_tuple{}; template struct make_indexes_impl; template struct make_indexes_impl, T, Types...> { typedef typename make_indexes_impl, Types...>::type type; }; template struct make_indexes_impl > { typedef index_tuple type; }; template struct make_indexes : make_indexes_impl<0, index_tuple<>, Types...> {}; 

Теперь код, который выполняет эту работу, не такой большой:

  // ----------UNPACK TUPLE AND APPLY TO FUNCTION --------- #include  #include  using namespace std; template Ret apply_helper( Ret (*pf)(Args...), index_tuple< Indexes... >, tuple&& tup) { return pf( forward( get(tup))... ); } template Ret apply(Ret (*pf)(Args...), const tuple& tup) { return apply_helper(pf, typename make_indexes::type(), tuple(tup)); } template Ret apply(Ret (*pf)(Args...), tuple&& tup) { return apply_helper(pf, typename make_indexes::type(), forward>(tup)); } 

Тест показан ниже:

 // --------------------- 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 tup(23, 4.5); apply(one, tup); int d = apply(two, std::make_tuple(2)); return 0; } 

Я не большой эксперт на других языках, но я предполагаю, что если эти языки не имеют такой функциональности в их меню, нет никакого способа сделать это. По крайней мере, с C ++ вы можете, и я думаю, что это не так сложно …

Я считаю, что это самое элегантное решение (и оно оптимально пересылается):

 #include  #include  #include  #include  template struct Apply { template static inline auto apply(F && f, T && t, A &&... a) -> decltype(Apply::apply( ::std::forward(f), ::std::forward(t), ::std::get(::std::forward(t)), ::std::forward(a)... )) { return Apply::apply(::std::forward(f), ::std::forward(t), ::std::get(::std::forward(t)), ::std::forward(a)... ); } }; template<> struct Apply<0> { template static inline auto apply(F && f, T &&, A &&... a) -> decltype(::std::forward(f)(::std::forward(a)...)) { return ::std::forward(f)(::std::forward(a)...); } }; template inline auto apply(F && f, T && t) -> decltype(Apply< ::std::tuple_size< typename ::std::decay::type >::value>::apply(::std::forward(f), ::std::forward(t))) { return Apply< ::std::tuple_size< typename ::std::decay::type >::value>::apply(::std::forward(f), ::std::forward(t)); } 

Пример использования:

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

К сожалению, GCC (по крайней мере 4.6) не может скомпилировать это с помощью «sorry, unimplemented: mangling overload» (что просто означает, что компилятор еще не полностью реализует спецификацию C ++ 11), и поскольку он использует вариативные шаблоны, работать в MSVC, поэтому он более или менее бесполезен. Однако, когда есть компилятор, который поддерживает спецификацию, это будет лучший подход IMHO. (Примечание: изменить это невозможно, так что вы можете обойти недостатки в GCC или реализовать его с помощью Boost Preprocessor, но это разрушает элегантность, поэтому это версия, которую я публикую.)

GCC 4.7 теперь полностью поддерживает этот код.

Редактировать: добавляется вперед по фактическому вызову функции для поддержки ссылочной формы rvalue * это в случае, если вы используете clang (или если кто-то еще на самом деле обходит его добавление).

Изменить: добавлен отсутствующий вперед объект функции в корпусе функции нечлена. Благодаря pheedbaq за то, что он отсутствовал.

Edit: И вот версия C ++ 14, так как она намного приятнее (на самом деле не компилируется):

 #include  #include  #include  #include  template struct Apply { template static inline auto apply(F && f, T && t, A &&... a) { return Apply::apply(::std::forward(f), ::std::forward(t), ::std::get(::std::forward(t)), ::std::forward(a)... ); } }; template<> struct Apply<0> { template static inline auto apply(F && f, T &&, A &&... a) { return ::std::forward(f)(::std::forward(a)...); } }; template inline auto apply(F && f, T && t) { return Apply< ::std::tuple_size< ::std::decay_t >::value>::apply(::std::forward(f), ::std::forward(t)); } 

Вот версия для функций-членов (не проверена очень!):

 using std::forward; // You can change this if you like unreadable code or care hugely about namespace pollution. template struct ApplyMember { template static inline auto apply(C&& c, F&& f, T&& t, A&&... a) -> decltype(ApplyMember::apply(forward(c), forward(f), forward(t), std::get(forward(t)), forward(a)...)) { return ApplyMember::apply(forward(c), forward(f), forward(t), std::get(forward(t)), forward(a)...); } }; template<> struct ApplyMember<0> { template static inline auto apply(C&& c, F&& f, T&&, A&&... a) -> decltype((forward(c)->*forward(f))(forward(a)...)) { return (forward(c)->*forward(f))(forward(a)...); } }; // C is the class, F is the member function, T is the tuple. template inline auto apply(C&& c, F&& f, T&& t) -> decltype(ApplyMember::type>::value>::apply(forward(c), forward(f), forward(t))) { return ApplyMember::type>::value>::apply(forward(c), forward(f), forward(t)); } 
 // Example: class MyClass { public: void foo(int i, bool b); }; MyClass mc; std::tuple t = make_tuple(20, false); void m() { apply(&mc, &MyClass::foo, t); } 
 template auto apply_impl(F&& f, Tuple&& t, std::index_sequence) { return std::forward(f)(std::get(std::forward(t))...); } template auto apply(F&& f, Tuple&& t) { using Indices = std::make_index_sequence>::value>; return apply_impl(std::forward(f), std::forward(t), Indices()); } 

Это адаптировано из проекта C ++ 14 с использованием index_sequence. Я мог бы предложить применить его в будущем стандарте (TS).

В C ++ 17 вы можете сделать это:

 std::apply(the_function, the_tuple); 

Это уже работает в Clang ++ 3.9, используя std :: experimental :: apply.

Отвечая на комментарий, говорящий, что это не сработает, если шаблон the_function , следующее:

 #include  template  void my_func(T &&t, U &&u) {} int main(int argc, char *argv[argc]) { std::tuple my_tuple; std::apply([](auto &&... args) { my_func(args...); }, my_tuple); return 0; } 

Эта работа представляет собой упрощенное решение общей проблемы передачи наборов перегрузки и шаблона функции, где ожидается функция. Общее решение (которое заботится о совершенной переадресации, constexprness и noexcept-ness) представлено здесь: https://blog.tartanllama.xyz/passing-overload-sets/ .

Новость выглядит не очень хорошо.

Прочитав только что выпущенный проект стандарта , я не вижу встроенного в него решения, что кажется странным.

Лучшее место, чтобы спросить о таких вещах (если вы еще этого не сделали), является comp.lang.c ++. Модерируется, потому что некоторые люди участвуют в составлении стандартного сообщения там регулярно.

Если вы проверите эту тему , у кого-то будет тот же вопрос (может быть, это вы, и в этом случае вы найдете весь этот ответ немного расстроенным!), И предлагаются несколько прикладов.

Я просто задавался вопросом, было бы проще заставить функцию принять tuple , поскольку преобразование таким образом проще. Но это означает, что все функции должны принимать кортежи в качестве аргументов, для максимальной гибкости, и поэтому просто демонстрирует странность не предоставления встроенного расширения кортежа для использования пакета аргументов.

Обновление: ссылка выше не работает – попробуйте вставить это:

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

Все эти реализации хороши. Но из-за использования указателя на функцию-член-компилятор часто не может встроить вызов целевой функции (по крайней мере, gcc 4.8 не может, независимо от того, почему gcc не может встроить указатели функций, которые можно определить? )

Но все меняется, если указатель отправки на функцию-член в качестве аргументов шаблона, а не как параметры функции:

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

И использование:

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

Доказательство настойчивости 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::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....) 

Плюс это единственное решение, которое работает с шаблонами.

1) если у вас есть готовая структура parameter_pack как аргумент функции, вы можете просто использовать std :: tie следующим образом:

 template  void tie_func(std::tuple t, Args&... args) { std::tie(args...) = t; } int main() { std::tuple 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  #include  #include  template struct apply_wrap { template static R applyTuple( std::function& f, const std::tuple& t, UnpackedArgs... args ) { return apply_wrap::applyTuple( f, t, std::get( t ), args... ); } }; template<> struct apply_wrap<0> { template static R applyTuple( std::function& f, const std::tuple&, UnpackedArgs... args ) { return f( args... ); } }; template R applyTuple( std::function& f, std::tuple const& t ) { return apply_wrap::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(&fac); cout << applyTuple(f, t); } 

Как насчет этого:

 // Warning: NOT tested! #include  #include  #include  #include  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, tuple const &t, Func &&f, Args &&...a ) -> decltype( forward(f)(declval()...) ) { return forward( f )( forward(a)... ); } template < size_t Index, typename Func, typename ...T, typename ...Args > auto explode_tuple( integral_constant, tuple const&t, Func &&f, Args &&...a ) -> decltype( forward(f)(declval()...) ) { return explode_tuple( integral_constant{}, t, forward(f), get(t), forward(a)... ); } } template < typename Func, typename ...T > auto run_tuple( Func &&f, tuple const &t ) -> decltype( forward(f)(declval()...) ) { return detail::explode_tuple( integral_constant{}, t, forward(f) ); } template < typename Tret, typename ...T > Tret func_T( tuple const &t ) { return run_tuple( &func, t ); } 

run_tuple функции run_tuple принимает заданный кортеж и передает его отдельные элементы в заданную функцию. Он выполняет свою работу, рекурсивно называя свои вспомогательные шаблоны функций explode_tuple . Важно, чтобы run_tuple размер кортежа explode_tuple ; это число действует как счетчик количества элементов для извлечения.

Если кортеж пуст, run_tuple вызывает первую версию explode_tuple с удаленной функцией в качестве единственного другого аргумента. Удаленная функция вызывается без аргументов, и мы закончили. Если кортеж не пуст, большее число передается во вторую версию explode_tuple вместе с удаленной функцией. Рекурсивный вызов explode_tuple производится с теми же аргументами, за исключением того, что число счетчиков уменьшается на единицу и (ссылка на) последний элемент explode_tuple как аргумент после удаленной функции. В рекурсивном вызове либо счетчик не равен нулю, а другой вызов выполняется с повторным уменьшением счетчика, а элемент next-unreferenced вставляется в список аргументов после удаленной функции, но перед другими вставленными аргументами, или счетчик достигает ноль и удаленная функция вызывается со всеми аргументами, накопленными после нее.

Я не уверен, что у меня есть синтаксис для правильного форматирования определенной версии шаблона функции. Я думаю, вы можете использовать указатель к функции как объект функции; компилятор автоматически ее исправит.

Я оцениваю MSVS 2013RC, и в некоторых случаях он не смог скомпилировать некоторые из предыдущих решений, предлагаемых здесь. Например, MSVS не сможет скомпилировать «авто» возврат, если слишком много параметров функции из-за ограничения на расширение пространства имен (я отправил эту информацию в Microsoft, чтобы ее исправить). В других случаях нам нужен доступ к возврату функции, хотя это также можно сделать с помощью lamda: следующие два примера дают тот же результат.

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

И еще раз спасибо тем, кто разместил ответы здесь передо мной, я бы не получил этого без этого … так вот это:

 template struct apply_impl { template static inline auto apply_tuple(F&& f, T&& t, A&&... a) -> decltype(apply_impl::apply_tuple(std::forward(f), std::forward(t), std::get(std::forward(t)), std::forward(a)...)) { return apply_impl::apply_tuple(std::forward(f), std::forward(t), std::get(std::forward(t)), std::forward(a)...); } template static inline auto apply_tuple(C*const o, F&& f, T&& t, A&&... a) -> decltype(apply_impl::apply_tuple(o, std::forward(f), std::forward(t), std::get(std::forward(t)), std::forward(a)...)) { return apply_impl::apply_tuple(o, std::forward(f), std::forward(t), std::get(std::forward(t)), std::forward(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 static inline auto apply_tuple(F&& f, T&& t, A&&... a) -> decltype(std::forward(f)(std::get<0>(std::forward(t)), std::get<1>(std::forward(t)), std::get<2>(std::forward(t)), std::get<3>(std::forward(t)), std::get<4>(std::forward(t)), std::get<5>(std::forward(t)), std::forward(a)...)) { return std::forward(f)(std::get<0>(std::forward(t)), std::get<1>(std::forward(t)), std::get<2>(std::forward(t)), std::get<3>(std::forward(t)), std::get<4>(std::forward(t)), std::get<5>(std::forward(t)), std::forward(a)...); } template static inline auto apply_tuple(C*const o, F&& f, T&& t, A&&... a) -> decltype((o->*std::forward(f))(std::get<0>(std::forward(t)), std::get<1>(std::forward(t)), std::get<2>(std::forward(t)), std::get<3>(std::forward(t)), std::get<4>(std::forward(t)), std::get<5>(std::forward(t)), std::forward(a)...)) { return (o->*std::forward(f))(std::get<0>(std::forward(t)), std::get<1>(std::forward(t)), std::get<2>(std::forward(t)), std::get<3>(std::forward(t)), std::get<4>(std::forward(t)), std::get<5>(std::forward(t)), std::forward(a)...); } }; #endif template<> struct apply_impl<0> { template static inline auto apply_tuple(F&& f, T&&, A&&... a) -> decltype(std::forward(f)(std::forward(a)...)) { return std::forward(f)(std::forward(a)...); } template static inline auto apply_tuple(C*const o, F&& f, T&&, A&&... a) -> decltype((o->*std::forward(f))(std::forward(a)...)) { return (o->*std::forward(f))(std::forward(a)...); } }; // Apply tuple parameters on a non-member or static-member function by perfect forwarding template inline auto apply_tuple(F&& f, T&& t) -> decltype(apply_impl::type>::value>::apply_tuple(std::forward(f), std::forward(t))) { return apply_impl::type>::value>::apply_tuple(std::forward(f), std::forward(t)); } // Apply tuple parameters on a member function template inline auto apply_tuple(C*const o, F&& f, T&& t) -> decltype(apply_impl::type>::value>::apply_tuple(o, std::forward(f), std::forward(t))) { return apply_impl::type>::value>::apply_tuple(o, std::forward(f), std::forward(t)); } 

Расширяя решение @ David, вы можете написать рекурсивный шаблон, который

  1. Не использует семантику (overly verbose, imo) integer_sequence
  2. Не использует дополнительный временный шаблонный параметр int N для подсчета рекурсивных итераций
  3. (Необязательно для статических / глобальных функторов) использует функтор в качестве параметра шаблона для оптимизации времени компиляции

Например:

 template  struct static_functor { template  static inline auto apply(const std::tuple& t, Args_tmp... args) -> decltype(func(std::declval()...)) { return static_functor::apply(t, args..., std::get(t)); } template  static inline auto apply(const std::tuple& t, T... args) -> decltype(func(args...)) { return func(args...); } }; static_functor::apply(my_tuple); 

В качестве альтернативы, если ваш функтор не задан во время компиляции (например, экземпляр-экземпляр constexpr или выражение lambda), вы можете использовать его как параметр функции вместо параметра шаблона classа и фактически удалить содержащийся class целиком :

 template  inline auto apply_functor(F&& func, const std::tuple& t, Args_tmp... args) -> decltype(func(std::declval()...)) { return apply_functor(func, t, args..., std::get(t)); } template  inline auto apply_functor(F&& func, const std::tuple& t, T... args) -> decltype(func(args...)) { return func(args...); } apply_functor(&myFunc, my_tuple); 

Для вызовов-указателей-указателей-членов можно отрегулировать любой из приведенных выше fragmentов кода так же, как в ответе @ Дэвида.

объяснение

В отношении второй части кода существуют две функции шаблона: первая принимает функтор func , кортеж t с типами T... и args типа args типов Args_tmp... При вызове он рекурсивно добавляет объекты из t в пакет параметров по одному, начиная с начала ( 0 ) и заканчивая, и снова вызывает функцию с новым пакетом добавленных параметров.

Подпись второй функции почти идентична первой, за исключением того, что она использует тип T... для args пакета параметров. Таким образом, как только args в первой функции полностью заполняются значениями из t , это тип будет T... (в psuedo-code, typeid(T...) == typeid(Args_tmp...) ) и поэтому компилятор вместо этого вызовет вторую перегруженную функцию, которая, в свою очередь, вызовет func(args...) .

Код в примере статического функтора работает одинаково, вместо этого вместо функтора вместо него используется аргумент шаблона classа.

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 auto get_args_as_tuple(Args... args) -> std::tuple { return std::make_tuple(args); } 

This simple solution works for me:

 template void unwrap_tuple(std::tuple* tp) { std::cout << "And here I have the tuple types, all " << sizeof...(T) << " of them" << std::endl; } int main() { using TupleType = std::tuple; unwrap_tuple((TupleType*)nullptr); // trick compiler into using template param deduction } 
  • Как легко инициализировать список кортежей?
  • Давайте будем гением компьютера.