标准库中是否存在类型级别的左折叠元函数?
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
如果 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