Рекурсивно преобразовать std :: tuple в std :: variant - PullRequest
2 голосов
/ 06 мая 2020

Требуется представление о том, какой метод использовать для объявления типа std::variant, содержащего все типы, включенные в данный std::tuple и его подкортежи (если элемент также является кортежем) рекурсивно.

Например,

std::tuple<int, std::tuple<int, double, std::tuple<float, double, std::string>>>

преобразуется в

std::variant<int, double, float, std::string>

короче, мне нужно включить все уникальные типы в std::variant.

1 Ответ

2 голосов
/ 06 мая 2020

С Boost.Mp11 это не так уж плохо.

Первый шаг - рекурсивно сгладить список ввода. У нас есть mp_flatten, но это только одно сглаживание - нам нужно вызывать его рекурсивно. Возможно, есть лучший способ сделать это, но лучшее, что я придумал до сих пор, - это использовать mp_iterate с функцией, которая сглаживает, только если это что-то делает:

// maybe_flatten succeeds only if it actually flattens
// (once we're flat, it's ill-formed, we use that a terminating condition for mp_iterate)
template <typename L,
    typename U=mp_flatten<L>,
    typename = std::enable_if_t<not mp_same<L, U>::value>>
using maybe_flatten = U;

template <typename L>
using recursive_flatten = mp_back<mp_iterate<L, mp_identity_t, maybe_flatten>>;

Как только у нас есть a recursive_flatten, тогда все, что нам нужно сделать, это убедиться, что типы уникальны, и переименовать его в вариант:

template <typename L>
using to_variant = mp_rename<mp_unique<recursive_flatten<L>>, std::variant>;

Demo .

Я здесь экспериментировал с метафункцией потоковой передачи (а-ля Clojure ->), чтобы вы могли писать вызываемые функции по порядку. Не уверен, что лучше:

template <typename L>
using recursive_flatten2 = thread<
    mp_iterate<L, mp_identity_t, maybe_flatten>,
    mp_back>;    

template <typename L>
using to_variant2 = thread_q<
    L,
    mp_quote<recursive_flatten2>,
    mp_quote<mp_unique>,
    mp_bind_q<mp_quote<mp_apply_q>, mp_quote<std::variant>, _1>
    >;

Демо с потоком .

...