标准库中是否存在类型级别的左折叠元函数?

Does there exist a type level left-fold metafunction in the standard library?

如果 a,b,c,.. 表示类型,则让 (a,b) 成为类型 std::pair<a,b> 我正在寻找地图,F,这样

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

它是否以标准库中的某个现有名称存在?如果没有,是否有另一个图书馆 它在其中实现还是很容易实现,我太笨不知道该怎么做?

我认为这个基本上必须是递归的。标准库中没有这样的东西,这一次我想不出 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


或者,我想,如果你真的讨厌你的读者,你可以把它变成 single alias:

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>;

我喜欢@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>
        >);

这是一个demo