Существует ли метафункция левого сгиба уровня типа в стандартной библиотеке? - PullRequest
1 голос
/ 01 мая 2020

Если a,b,c,.. обозначает типы, тогда пусть (a,b) будет типом std::pair<a,b> Я ищу карту, F, такую, что

    F : ((((a,b),c),d),...))) -> std::tuple<a,b,c,d...>

Существует ли это под каким-либо существующим именем в стандартная библиотека? Если нет, есть ли другая библиотека, в которой это делается, или это легко реализовать, и я просто слишком туп, чтобы знать, как это сделать?

Ответы [ 2 ]

4 голосов
/ 01 мая 2020

Я думаю, что этот в основном должен быть рекурсивным. В стандартной библиотеке такого нет, и на этот раз я не могу придумать однострочный Boost.Mp11 .

namespace impl {
    template <typename T>
    struct unfold_t {
        using type = std::tuple<T>;
    };

    template <typename A, typename B>
    struct unfold_t<std::pair<A, B>> {
        using type = mp_push_back<typename unfold_t<A>::type, B>;
    };
}

template <typename T>
using unfold = typename impl::unfold_t<T>::type;

С помощью T. C. Новейшая редакция Mp11 (1.73) имеет алгоритм с именем mp_iterate, который мы можем использовать таким образом.

Учитывая std::pair<std::pair<X, Y>, Z>, если мы применяем mp_first повторно (как R), мы получаем последовательность:

  • std::pair<std::pair<X, Y>, Z>
  • std::pair<X, Y>
  • X

Тогда, если мы применим mp_second к этой последовательности, мы получим:

  • Z
  • Y
  • плохо сформирован

Это довольно близко. Нам нужно это X. Поэтому нам нужна более сложная метафункция для F: нам нужно получить второе значение, если это возможно. Для этого есть метафункция:

template <typename L>
using second_or_self = mp_eval_or<L, mp_second, L>;

А теперь mp_iterate<T, second_or_self, mp_first> дает нам mp_list<Z, Y, X>. Все, что нам нужно сделать в этот момент, это перевернуть его и превратить в std::tuple:

template <typename L>
using unfold = mp_rename<mp_reverse<
    mp_iterate<L, second_or_self, mp_first>>,
    std::tuple>;

Теперь, когда Boost.173 работает на проводнике компилятора, demo .

Или, я полагаю, если вы действительно ненавидите своих читателей, вы можете сделать это одиночным псевдонимом :

template <typename L>
using unfold = mp_rename<mp_reverse<
    mp_iterate_q<L,
        mp_bind<mp_eval_or_q, _1, mp_quote<mp_second>, _1>,
        mp_quote<mp_first>>>,
    std::tuple>;
0 голосов
/ 02 мая 2020

Мне нравится решение @Barry и, в частности, имя unfold для этой мета-функции. Тем не менее, я думаю, что вы можете реализовать это довольно легко, используя частичные специализации, без использования boost.Mp11, и вам может показаться, что это легче понять.

Сначала предоставьте базовый вариант для типа, который уже полностью развернут в tuple:

template <typename ...Ts>
struct unfold_impl { using type = std::tuple<Ts...>; };

, а затем укажите специализацию, если еще осталось развернуть pair:

template <typename A, typename B, typename ...Ts>
struct unfold_impl<std::pair<A,B>, Ts...> : unfold_impl<A, B, Ts...> {};

и, наконец, предоставьте удобный шаблон псевдонима:

template <typename ...Ts>
using unfold = typename unfold_impl<Ts...>::type;

и все.

Вы можете проверить, работает ли он, например так:

static_assert(
    std::is_same_v<
        unfold<std::pair<std::pair<std::pair<int, long>, char>, double>>,
        std::tuple<int, long, char, double>
        >);

Вот демо

...