C++11: я могу перейти от нескольких аргументов к кортежу, но могу ли я перейти от кортежа к нескольким аргументам?
Возможный дубликат:
Как развернуть кортеж в аргументы функции шаблона переменной?
"Распаковка" кортежа для вызова соответствующего указателя на функцию
В шаблонах C++11 есть ли способ использовать кортеж в качестве отдельных аргументов (возможно, шаблона) функции?
Пример:
Допустим, у меня есть эта функция:
void foo(int a, int b)
{
}
И у меня есть кортеж auto bar = std::make_tuple(1, 2)
,
Могу ли я использовать это, чтобы позвонить foo(1, 2)
в шаблонном виде?
Я не имею в виду просто foo(std::get<0>(bar), std::get<1>(bar))
так как я хочу сделать это в шаблоне, который не знает количество аргументов.
Более полный пример:
template<typename Func, typename... Args>
void caller(Func func, Args... args)
{
auto argtuple = std::make_tuple(args...);
do_stuff_with_tuple(argtuple);
func(insert_magic_here(argtuple)); // <-- this is the hard part
}
Я должен отметить, что я предпочел бы не создавать один шаблон, который работает для одного аргумента, другой, который работает для двух, и т.д…
2 ответа
Попробуйте что-то вроде этого:
// implementation details, users never invoke these directly
namespace detail
{
template <typename F, typename Tuple, bool Done, int Total, int... N>
struct call_impl
{
static void call(F f, Tuple && t)
{
call_impl<F, Tuple, Total == 1 + sizeof...(N), Total, N..., sizeof...(N)>::call(f, std::forward<Tuple>(t));
}
};
template <typename F, typename Tuple, int Total, int... N>
struct call_impl<F, Tuple, true, Total, N...>
{
static void call(F f, Tuple && t)
{
f(std::get<N>(std::forward<Tuple>(t))...);
}
};
}
// user invokes this
template <typename F, typename Tuple>
void call(F f, Tuple && t)
{
typedef typename std::decay<Tuple>::type ttype;
detail::call_impl<F, Tuple, 0 == std::tuple_size<ttype>::value, std::tuple_size<ttype>::value>::call(f, std::forward<Tuple>(t));
}
Пример:
#include <cstdio>
int main()
{
auto t = std::make_tuple("%d, %d, %d\n", 1,2,3);
call(std::printf, t);
}
С некоторой дополнительной магией и использованием std::result_of
Возможно, вы также можете заставить все это возвращать правильное возвращаемое значение.
Создайте "кортеж индекса" (кортеж целых чисел времени компиляции), а затем перешлите к другой функции, которая выводит индексы как пакет параметров и использует их в расширении пакета для вызова std::get
на кортеже:
#include <redi/index_tuple.h>
template<typename Func, typename Tuple, unsigned... I>
void caller_impl(Func func, Tuple&& t, redi::index_tuple<I...>)
{
func(std::get<I>(t)...);
}
template<typename Func, typename... Args>
void caller(Func func, Args... args)
{
auto argtuple = std::make_tuple(args...);
do_stuff_with_tuple(argtuple);
typedef redi::to_index_tuple<Args...> indices;
caller_impl(func, argtuple, indices());
}
Моя реализация index_tuple
находится по адресу https://gitlab.com/redistd/redistd/blob/master/include/redi/index_tuple.h но он использует псевдонимы шаблонов, поэтому, если ваш компилятор не поддерживает, вам нужно изменить его для использования C++03-стиле "шаблон typedefs" и заменить последние две строки caller
с
typedef typename redi::make_index_tuple<sizeof...(Args)>::type indices;
caller_impl(func, argtuple, indices());
Аналогичная утилита была стандартизирована как std::index_sequence
в C++14 (см. index_seq.h для автономной реализации C++11).