Подтвердить что ты не робот

С++ 11: я могу перейти от нескольких аргументов к кортежу, но могу ли я перейти от кортежа к нескольким аргументам?

Возможный дубликат:
Как расширить кортеж в аргументы функции вариационной матрицы?
"распаковать" кортеж, чтобы вызвать соответствующий указатель функции

В шаблонах С++ 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  
}

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

4b9b3361

Ответ 1

Попробуйте что-то вроде этого:

// 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 вы, вероятно, также можете вернуть все верное возвращаемое значение.

Ответ 2

Создайте "индексный кортеж" (кортеж целых чисел компиляции), затем перейдите к другой функции, которая выводит индексы в виде пакета параметров и использует их в расширении пакета для вызова 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 но он опирается на псевдонимы шаблонов, поэтому, если ваш компилятор не поддерживает то, что вам нужно будет изменить, чтобы использовать "шаблоны typedefs" в стиле С++ 03 и заменить последние две строки caller на

    typedef typename redi::make_index_tuple<sizeof...(Args)>::type indices;
    caller_impl(func, argtuple, indices());

Аналогичная утилита была стандартизирована как std::index_sequence в С++ 14 (см. index_seq.h для автономной реализации С++ 11).