Вопрос по c++, c++11, variadic-templates, templates – C ++ 11: я могу перейти от нескольких аргументов к кортежу, но могу ли я перейти от кортежа к нескольким аргументам? [Дубликат]

30

Possible Duplicate:
How do I expand a tuple into variadic template function's arguments?
“unpacking” a tuple to call a matching function pointer

В шаблонах 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)) поскольку я хочу сделать это в шаблоне, который не знает количество аргументов.

More complete example:

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  
}

Следует отметить, что я предпочитаю не создавать один шаблон, который работает для одного аргумента, другой - для двух и т. Д. & # X2026;

Конечно. Вы хотите что-то вродеtemplate <typename F, typename Tuple, int N...> call(F f, Tuple const & t) { f(std::get<N>(t)...); }, Теперь просто заполните пробелы :-) Kerrek SB
(Это должно было бытьint ...N, конечно.) Kerrek SB
@Thomas: вам придется создать небольшой диспетчерский жгут, который соберет целочисленный пакетN...и частично специализируется, когдаN == std::tuple_size<Tuple>::valueВы хотите вызвать оригинальную функцию так, как я предложил. Kerrek SB
Вы имеете в виду пропуск вариационных шаблонов и создание несколькихcaller() шаблоны вместо? Thomas

Ваш Ответ

2   ответа
4

индексный кортеж & quot; (кортеж целых чисел времени компиляции), а затем переходит к другой функции, которая выводит индексы как пакет параметров и использует их в расширении пакета для вызова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 "template 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).

@underscore_d, да, это очевидный способ сделать это.
Хм, думаю, у меня получилось_impl функция эквивалентна на основеT_ReturnedObject и заставить его вызывать ctor этого объекта со всеми распакованными вещами. Я предполагаю, что это был "очевидный трюк" Я упомянул!
не могли бы вы объяснитьtype::template синтаксис?
@JonathanWakely Очень мило. Может быть, я упускаю очевидный трюк, но есть ли способ применитьtuple например, когда рассматриваемая функция является конструктором ... или это требует слишком много магии? : D
58

// 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 :: tuple, который я обнаружил в stackoverflow, и у него есть половина голосов гораздо худших решений ...
Это хорошо в качестве упражнения в мастурбации шаблона, но вы действительно хотите написатьcall_impl<F, Tuple, 0 == std::tuple_size<ttype>::value, std::tuple_size<ttype>::value>::call(f, std::forward<Tuple>(t)) где вы хотите расширить кортеж?
Просто предложение, вы можете броситьauto там для вызова, так что вы можете использовать возвращаемое значение функции, кстати, кроме того, что действительно нравится решение
@JonathanWakely:call_impl это деталь реализации - пользователи никогда не называют это напрямую, глобальноcall это все, с чем взаимодействуют пользователи. Этот пример неясен?
Ах, нет, я просто не выглядела правильно, подумала яcall была замена для OP 'scaller и поэтому громоздкое использованиеcall_impl произошло в коде пользователя.

Похожие вопросы