Как превратить пакет параметров в нечто иное, чем std :: tuple? - PullRequest
2 голосов
/ 21 апреля 2020

Это лучше объяснить на примере:

template <typename T1, typename T2>
struct OnePair
{
    using TupleOfArgs = std::tuple<T1, T2>;
    using TupleOfPairs = std::tuple<std::pair<T1, T2>>;
};

template <typename T1, typename T2, typename T3, typename T4>
struct TwoPairs
{
    using TupleOfArgs = std::tuple<T1, T2, T3, T4>;
    using TupleOfPairs = std::tuple<std::pair<T1, T2>, std::pair<T3, T4>>;
};

template <typename... Args>
struct NPairs
{
    using TupleOfArgs = std::tuple<Args...>;
//  using TupleOfPairs = ???
};

OnePair определяет кортеж с одной парой. TwoPairs определяет кортеж с двумя парами.

Как определить TupleOfPairs в NPairs, чтобы он преобразовывал пакет параметров в std :: tuple пар?

Возможно ли добиться этого с помощью std библиотека? Может быть, с boost :: mpl?

Два ответа, оба великолепны. @chris использует итерационный метод, а @aschepler использует рекурсивное решение. Лично я нашел рекурсивное решение проще для понимания.

Ответы [ 2 ]

2 голосов
/ 21 апреля 2020

Вы можете использовать знакомый трюк с индексной последовательностью, но с половиной размера ( живой пример ):

static constexpr auto get_tuple() {
    constexpr auto N = sizeof...(Args);
    static_assert(N%2 == 0);

    using ArgsTuple = std::tuple<Args...>;
    auto impl = []<std::size_t... Is>(std::index_sequence<Is...>) {
        return std::tuple<
            // Is goes from 0 to N/2, representing Ith pair
            std::pair<std::tuple_element_t<Is*2, ArgsTuple>, std::tuple_element_t<Is*2 + 1, ArgsTuple>>...
        >{};
    };

    return impl(std::make_index_sequence<N/2>{});
}

using TupleOfArgs = decltype(get_tuple());

Если у вас нет C ++ 20, вы ' Придется расширить лямбда-функцию до функции, вместо того, чтобы использовать хорошее расширение последовательности встроенного индекса, но ядро ​​все еще функционирует. Это может также быть немного чище с использованием списка типов вместо std::tuple, но это выполнимо.

1 голос
/ 21 апреля 2020

Вот один простой способ с рекурсивным помощником:

template <typename PairsTuple, typename... Ts>
struct ZipPairs;

template <typename PairsTuple>
struct ZipPairs<PairsTuple> { using type = PairsTuple; };

template <typename... Pairs, typename T1, typename T2, typename... Ts>
struct ZipPairs<std::tuple<Pairs...>, T1, T2, Ts...>
{
    using type = typename ZipPairs<
        std::tuple<Pairs..., std::pair<T1, T2>>, Ts...>::type;
};

template <class... Args>
struct NPairs
{
    static_assert(sizeof...(Args) % 2 == 0);
    using TupleOfArgs = std::tuple<Args...>;
    using TupleOfPairs = typename ZipPairs<std::tuple<>, Args...>::type;
};
...