Я думаю, что этот в основном должен быть рекурсивным. В стандартной библиотеке такого нет, и на этот раз я не могу придумать однострочный 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
к этой последовательности, мы получим:
Это довольно близко. Нам нужно это 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>;