概述
Mp11 是一个 C++11 元编程库,用于在编译时操作包含类型的 C++ 数据结构。它基于模板别名和变长模板,实现了 “Simple C++ metaprogramming” 文章及其 续篇中所概述的方法。强烈建议在继续阅读本文档之前阅读这些文章。
Mp11 构建所依据的通用原则是,算法和元函数的形式为 F<T…> 的模板别名,数据结构的形式为 L<T…> 的列表,库对 L 没有特定要求。mp_list<T…> 是内置的列表类型,但 std::tuple<T…>、std::pair<T1, T2> 和 std::variant<T…> 也是完全合法的列表类型。当然,由于 std::pair<T1, T2> 只有两个元素,它不能调整大小,因此无法与需要添加或删除元素的算法一起使用。
此方法的另一个显著特点是,列表(L<T…>)与元函数(F<T…>)具有相同的形式,因此可以互用。例如,通过 mp_transform<std::add_pointer_t, std::tuple<int, float>> 将 std::add_pointer_t 应用于列表 std::tuple<int, float>,得到 std::tuple<int*, float*>。但我们也可以将 mp_list 应用于同一个 tuple
using R = mp_transform<mp_list, std::tuple<int, float>>;
得到 std::tuple<mp_list<int>, mp_list<float>>。
定义
列表 是一个类模板的实例化,该类模板(通常但并非必然是变长)的参数全部是类型,例如 mp_list<char[], void>、mp_list<>、std::tuple<int, float, char>、std::pair<int, float>、std::shared_ptr<X>。
元函数 是一个类模板或模板别名,其参数全部是类型,例如 std::add_pointer_t、std::is_const、mp_second、mp_push_front、mp_list、std::tuple、std::pair、std::shared_ptr,或者
template<class...> using F1 = void;
template<class T> using F2 = T*;
template<class... T> using F3 = std::integral_constant<std::size_t, sizeof...(T)>;
引号元函数 是一个具有名为 fn 的公共元函数成员的类,例如
struct Q1 { template<class...> using fn = void; };
struct Q2 { template<class T> using fn = T*; };
struct Q3 { template<class... T> using fn =
std::integral_constant<std::size_t, sizeof...(T)>; };
整数常量类型 是一个具有公共成员 value 的类,该成员是 C++ 意义上的整数常量。例如,std::integral_constant<int, 7>,或者
struct N { static int constexpr value = 2; };
集合 是一个元素唯一的列表。
映射 是一个列表的列表,内部列表至少有一个元素(键)。映射的键必须是唯一的。例如,
using M1 = std::tuple<std::pair<int, int*>, std::pair<float, float*>,
std::pair<void, void*>>;
using M2 = mp_list<mp_list<int, int*>, mp_list<float>,
mp_list<char, char[1], char[2]>>;
值列表 是一个模板类,其参数全部是值(非类型模板参数)。值列表匹配 template<auto…> class L,需要 C++17(因为 auto 模板参数是 C++17 特性)。
只有少数原始函数支持值列表。Mp11 主要关注类型操作。要处理值列表,通常的方法是使用 mp_rename 将值列表转换为类型列表,操作类型列表,然后使用 mp_rename_v 转换回值列表。
示例
生成测试用例
假设我们已经编写了一个元函数 result<T, U>
template<class T> using promote = typename std::common_type<T, int>::type;
template<class T, class U> using result =
typename std::common_type<promote<T>, promote<U>>::type;
它应该表示整数类型 T 和 U 上的算术运算的结果,例如 t + u。我们想测试 result<T, U> 对于各种 T 和 U 的组合是否给出正确的结果,因此我们编写函数
template<class T1, class T2> void test_result()
{
using T3 = decltype( T1() + T2() );
using T4 = result<T1, T2>;
std::cout << ( std::is_same<T3, T4>::value? "[PASS]": "[FAIL]" ) << std::endl;
}
然后需要多次调用它
int main()
{
test_result<char, char>();
test_result<char, short>();
test_result<char, int>();
test_result<char, unsigned>();
// ...
}
手动编写所有这些类型组合是繁琐、易出错的,而且最糟糕的是,令人厌烦。我们可以通过这种方式利用 Mp11 来自动化此任务
#include <boost/mp11.hpp>
#include <boost/core/demangle.hpp>
#include <type_traits>
#include <iostream>
#include <typeinfo>
using namespace boost::mp11;
template<class T> std::string name()
{
return boost::core::demangle( typeid(T).name() );
}
template<class T> using promote = typename std::common_type<T, int>::type;
template<class T, class U> using result =
typename std::common_type<promote<T>, promote<U>>::type;
template<class T1, class T2> void test_result( mp_list<T1, T2> const& )
{
using T3 = decltype( T1() + T2() );
using T4 = result<T1, T2>;
std::cout << ( std::is_same<T3, T4>::value? "[PASS] ": "[FAIL] " )
<< name<T1>() << " + " << name<T2>() << " -> " << name<T3>()
<< ", result: " << name<T4>() << std::endl;
}
int main()
{
using L = std::tuple<char, short, int, unsigned, long, unsigned long>;
tuple_for_each( mp_product<mp_list, L, L>(), [](auto&& x){ test_result(x); } );
}
它是如何工作的?
mp_product<F, L1, L2> 调用 F<T1, T2>,其中 T1 遍历 L1 的元素,T2 遍历 L2 的元素,如同执行两个嵌套循环一样。然后它返回这些结果的列表,类型与 L1 相同。
在我们的例子中,两个列表都是相同的 std::tuple,而 F 是 mp_list,因此 mp_product<mp_list, L, L> 将得到 std::tuple<mp_list<char, char>, mp_list<char, short>, mp_list<char, int>, …, mp_list<unsigned long, long>, mp_list<unsigned long, unsigned long>>。
然后我们默认构造此 tuple,并将其传递给 tuple_for_each。tuple_for_each(tp, f) 为每个 tuple 元素调用 f;我们使用一个(C++14) lambda 来调用 test_result。
在纯 C++11 中,我们不能使用带有 auto&& 参数的 lambda,因此我们必须将 test_result 制作成一个具有模板化 operator() 的函数对象,并直接将其传递给 tuple_for_each。
struct test_result
{
template<class T1, class T2> void operator()( mp_list<T1, T2> const& ) const
{
using T3 = decltype( T1() + T2() );
using T4 = result<T1, T2>;
std::cout << ( std::is_same<T3, T4>::value? "[PASS] ": "[FAIL] " )
<< name<T1>() << " + " << name<T2>() << " -> " << name<T3>()
<< ", result: " << name<T4>() << std::endl;
}
};
int main()
{
using L = std::tuple<char, short, int, unsigned, long, unsigned long>;
tuple_for_each( mp_product<mp_list, L, L>(), test_result() );
}
编写 common_type 特化
标准的 trait std::common_type 用于获取一个类型,该类型可以无损地转换为其所有参数。当默认实现(基于三元 ?: 运算符)不适用时,可以对其进行用户特化。
让我们为两个 std::tuple 参数编写一个 common_type 特化。为此,我们需要一个元函数,该元函数将 std::common_type 应用于每个元素对,并将结果收集到一个 tuple 中
template<class... T> using common_type_t =
typename std::common_type<T...>::type; // standard in C++14
template<class Tp1, class Tp2> using common_tuple =
mp_transform<common_type_t, Tp1, Tp2>;
然后特化 common_type 以使用它
namespace std
{
template<class... T1, class... T2>
struct common_type<std::tuple<T1...>, std::tuple<T2...>>:
mp_defer<common_tuple, std::tuple<T1...>, std::tuple<T2...>>
{
};
} // std
(对于多于两个参数,无需特化 std::common_type - 它会从二元情况合成适当的语义。)
这里的微妙之处在于使用了 mp_defer。我们可以定义一个嵌套的 type 来 common_tuple<std::tuple<T1…>, std::tuple<T2…>>,在所有有效情况下它仍然可以工作。但是,通过让 mp_defer 定义 type,我们使我们的特化对 SFINAE 友好。
也就是说,当我们的 common_tuple 导致替换失败而不是硬错误时,mp_defer 不会定义嵌套的 type,而 common_type_t(定义为 typename common_type<…>::type)也将导致替换失败。
另一个例子是假设的类型 expected<T, E…>,它表示成功返回一个 T 类型的值,或者返回一个错误代码,错误类型来自列表 E…。expected<T1, E1, E2, E3> 和 expected<T2, E1, E4, E5> 的公共类型是 expected<common_type_t<T1, T2>, E1, E2, E3, E4, E5>。也就是说,可能的返回值被合并为它们的公共类型,我们取错误类型集合的并集。
因此,
template<class T1, class E1, class T2, class E2> using common_expected =
mp_rename<mp_push_front<mp_unique<mp_append<E1, E2>>, common_type_t<T1, T2>>,
expected>;
namespace std
{
template<class T1, class... E1, class T2, class... E2>
struct common_type<expected<T1, E1...>, expected<T2, E2...>>:
mp_defer<common_expected, T1, mp_list<E1...>, T2, mp_list<E2...>>
{
};
} // std
在这里我们采取了不同的方法;我们没有将 expected 类型传递给 common_expected,而是传递了 T 类型和 E 类型列表。这使我们的工作更轻松。mp_unique<mp_append<E1, E2>> 给出了 E1 和 E2 的连接,去除了重复项;然后我们通过 mp_push_front 将 common_type_t<T1, T2> 添加到前面;最后,我们将结果 mp_list mp_rename 为 expected。
修复 tuple_cat
文章 Simple C++11 metaprogramming 构建了一个标准函数 tuple_cat 的实现,最终结果如下所示
template<class L> using F = mp_iota<mp_size<L>>;
template<class R, class...Is, class... Ks, class Tp>
R tuple_cat_( mp_list<Is...>, mp_list<Ks...>, Tp tp )
{
return R{ std::get<Ks::value>(std::get<Is::value>(tp))... };
}
template<class... Tp,
class R = mp_append<std::tuple<>, typename std::remove_reference<Tp>::type...>>
R tuple_cat( Tp &&... tp )
{
std::size_t const N = sizeof...(Tp);
// inner
using list1 = mp_list<
mp_rename<typename std::remove_reference<Tp>::type, mp_list>...>;
using list2 = mp_iota_c<N>;
using list3 = mp_transform<mp_fill, list1, list2>;
using inner = mp_apply<mp_append, list3>;
// outer
using list4 = mp_transform<F, list1>;
using outer = mp_apply<mp_append, list4>;
//
return tuple_cat_<R>( inner(), outer(),
std::forward_as_tuple( std::forward<Tp>(tp)... ) );
}
然而,这个函数并不完全正确,因为它未能妥善处理某些情况。例如,尝试连接包含 move-only 元素的 tuple(如 unique_ptr)会失败
std::tuple<std::unique_ptr<int>> t1;
std::tuple<std::unique_ptr<float>> t2;
auto result = ::tuple_cat( std::move( t1 ), std::move( t2 ) );
尝试连接 const tuple 会失败
std::tuple<int> const t1;
std::tuple<float> const t2;
auto result = ::tuple_cat( t1, t2 );
最后,标准的 tuple_cat 被指定为处理任意类 tuple 类型(即,所有支持 tuple_size、tuple_element 和 get 的类型),而我们的实现仅处理 tuple 和 pair。例如,std::array 会失败
std::array<int, 2> t1{ 1, 2 };
std::array<float, 3> t2{ 3.0f, 4.0f, 5.0f };
auto result = ::tuple_cat( t1, t2 );
让我们逐一修复这些问题。对 move-only 类型的支持很容易,只要知道在哪里查找。问题在于我们传递给辅助函数 tuple_cat_ 的 Tp(正确地)是 tuple<unique_ptr<int>&&, unique_ptr<float>&&>,但 std::get<0>(tp) 仍然返回 unique_ptr<int>&,因为 tp 是一个左值。这种行为有点令人惊讶,但目的是防止意外的双重移动。
长话短说,我们需要在 tuple_cat_ 中使用 std::move(tp) 来使 tp 成为一个右值。
template<class R, class...Is, class... Ks, class Tp>
R tuple_cat_( mp_list<Is...>, mp_list<Ks...>, Tp tp )
{
return R{ std::get<Ks::value>(std::get<Is::value>(std::move(tp)))... };
}
接下来是 const 限定的 tuple。这里的问题是我们从输入 tuple 中剥离了引用,但没有剥离 const。因此,我们正在尝试使用 Mp11 算法处理 tuple<int> const 这样的类型,而这些类型不符合列表的概念。我们只需要也剥离限定符,通过定义一个标准库中莫名缺失的有用原语 remove_cv_ref 来实现
template<class T> using remove_cv_ref = typename std::remove_cv<
typename std::remove_reference<T>::type>::type;
然后使用 remove_cv_ref<Tp> 代替 typename std::remove_reference<Tp>::type。
template<class... Tp,
class R = mp_append<std::tuple<>, remove_cv_ref<Tp>...>>
R tuple_cat( Tp &&... tp )
{
std::size_t const N = sizeof...(Tp);
// inner
using list1 = mp_list<mp_rename<remove_cv_ref<Tp>, mp_list>...>;
// ...
最后是类 tuple 类型。到目前为止,我们利用了 std::pair 和 std::tuple 是有效的 Mp11 列表这一事实,但一般来说,任意类 tuple 类型并非如此,所以我们需要将它们转换为类 tuple。为此,我们需要定义一个元函数 from_tuple_like,它接受一个任意类 tuple 类型,并返回(在我们的例子中)相应的 mp_list。
严格来说,一个更具原则性的方法是返回 std::tuple,但在本例中 mp_list 会更方便。
我们需要的是,给定一个类 tuple 类型 Tp,得到 mp_list<std::tuple_element<0, Tp>::type, std::tuple_element<1, Tp>::type, …, std::tuple_element<N-1, Tp>::type>,其中 N 是 tuple_size<Tp>::value。以下是一种实现方法
template<class T, class I> using tuple_element =
typename std::tuple_element<I::value, T>::type;
template<class T> using from_tuple_like =
mp_product<tuple_element, mp_list<T>, mp_iota<std::tuple_size<T>>>;
(mp_iota<N> 是一个算法,它返回一个 mp_list,元素为 mp_size_t<0>、mp_size_t<1>、…、mp_size_t<N-1>。)
记住,mp_product<F, L1, L2> 执行相当于两个嵌套循环遍历 L1 和 L2 的元素,将 F 应用于两个变量并收集结果。在我们的例子中,L1 由单个元素 T 组成,因此只剩下第二个循环(在 mp_iota<N> 上,其中 N 是 tuple_size<T>),并且我们得到一个与 L1 类型相同(mp_list)的列表,内容为 tuple_element<T, mp_size_t<0>>、tuple_element<T, mp_size_t<1>>、…、tuple_element<T, mp_size_t<N-1>>。
为完整起见,这里是另一种实现相同结果的更传统的方法。
template<class T> using from_tuple_like =
mp_transform_q<mp_bind_front<tuple_element, T>, mp_iota<std::tuple_size<T>>>;
应用了所有这些修复之后,我们完全可用的 tuple_cat 现在看起来是这样的
template<class L> using F = mp_iota<mp_size<L>>;
template<class R, class...Is, class... Ks, class Tp>
R tuple_cat_( mp_list<Is...>, mp_list<Ks...>, Tp tp )
{
return R{ std::get<Ks::value>(std::get<Is::value>(std::move(tp)))... };
}
template<class T> using remove_cv_ref = typename std::remove_cv<
typename std::remove_reference<T>::type>::type;
template<class T, class I> using tuple_element =
typename std::tuple_element<I::value, T>::type;
template<class T> using from_tuple_like =
mp_product<tuple_element, mp_list<T>, mp_iota<std::tuple_size<T>>>;
template<class... Tp,
class R = mp_append<std::tuple<>, from_tuple_like<remove_cv_ref<Tp>>...>>
R tuple_cat( Tp &&... tp )
{
std::size_t const N = sizeof...(Tp);
// inner
using list1 = mp_list<from_tuple_like<remove_cv_ref<Tp>>...>;
using list2 = mp_iota_c<N>;
using list3 = mp_transform<mp_fill, list1, list2>;
using inner = mp_apply<mp_append, list3>;
// outer
using list4 = mp_transform<F, list1>;
using outer = mp_apply<mp_append, list4>;
//
return tuple_cat_<R>( inner(), outer(),
std::forward_as_tuple( std::forward<Tp>(tp)... ) );
}
计算返回类型
C++17 有一个标准的变体类型,称为 std::variant。它还定义了一个函数模板 std::visit,可用于将一个函数应用于一个或多个变体所包含的值。例如,如果变体 v1 包含 1,变体 v2 包含 2.0f,那么 std::visit(f, v1, v2) 将调用 f(1, 2.0f)。
然而,std::visit 有一个限制:除非所有可能的函数应用都具有相同的返回类型,否则它无法返回结果。例如,如果 v1 和 v2 都是 std::variant<short, int, float> 类型,
std::visit( []( auto const& x, auto const& y ){ return x + y; }, v1, v2 );
将因编译失败而告终,因为 x + y 的结果可能是 int 或 float,具体取决于 v1 和 v2 的内容。
一个可以容纳 int 或 float 的类型已经存在,令人惊讶地称为 std::variant<int, float>。让我们编写自己的函数模板 rvisit,它与 visit 相同,但返回一个 variant。
template<class F, class... V> auto rvisit( F&& f, V&&... v )
{
using R = /*...*/;
return std::visit( [&]( auto&&... x )
{ return R( std::forward<F>(f)( std::forward<decltype(x)>(x)... ) ); },
std::forward<V>( v )... );
}
这基本上是调用 std::visit 来执行工作,但我们传递给它的是一个 lambda,它与 f 相同,只是它将结果转换为通用类型 R。R 应该是 std::variant<…>,其中省略号表示调用 f 时使用所有可能的变体值组合的返回类型。
我们将首先定义一个辅助引号元函数 Qret<F>,它返回 F 应用于类型 T… 的参数的结果
template<class F> struct Qret
{
template<class... T> using fn =
decltype( std::declval<F>()( std::declval<T>()... ) );
};
事实证明,C++17 已经包含了一个元函数,该函数返回函数 F 应用于类型 T… 的结果:std::invoke_result_t<F, T…>。我们可以利用它来简化我们的 Qret
template<class F> struct Qret
{
template<class... T> using fn = std::invoke_result_t<F, T...>;
};
在 Mp11 中,这可以更简洁地表示为
using Qret = mp_bind_front<std::invoke_result_t, F>;
有了 Qret,返回类型的 variant 仅仅是将其应用于变体值的所有可能组合的问题。
using R = mp_product_q<Qret, remove_cv_ref<V>...>;
为什么这有效?mp_product<F, L1<T1…>, L2<T2…>, …, Ln<Tn…>> 返回 L1<F<U1, U2, …, Un>, …>,其中 Ui 遍历列表值的所有可能组合。因为在我们的例子中所有 Li 都是 std::variant,结果也将是 std::variant。(mp_product_q 与 mp_product 相同,但用于引号元函数,如我们的 Qret。)
还有一步。假设,如上所述,我们传递两个类型为 std::variant<short, int, float> 的变体,并且 F 是 []( auto const& x, auto const& y ){ return x + y; }。这将生成长度为 9 的 R,每个组合一个,但其中许多元素将是相同的,要么是 int 要么是 float,我们需要过滤掉重复项。所以,我们将结果传递给 mp_unique
using R = mp_unique<mp_product_q<Qret, remove_cv_ref<V>...>>;
然后我们就完成了。
#include <boost/mp11.hpp>
#include <boost/core/demangle.hpp>
#include <variant>
#include <type_traits>
#include <typeinfo>
#include <iostream>
using namespace boost::mp11;
template<class T> using remove_cv_ref = typename std::remove_cv<
typename std::remove_reference<T>::type>::type;
template<class F, class... V> auto rvisit( F&& f, V&&... v )
{
using Qret = mp_bind_front<std::invoke_result_t, F>;
using R = mp_unique<mp_product_q<Qret, remove_cv_ref<V>...>>;
return std::visit( [&]( auto&&... x )
{ return R( std::forward<F>(f)( std::forward<decltype(x)>(x)... ) ); },
std::forward<V>( v )... );
}
template<class T> std::string name()
{
return boost::core::demangle( typeid(T).name() );
}
template<class V> void print_variant( char const * n, V const& v )
{
std::cout << "(" << name<decltype(v)>() << ")" << n << ": ";
std::visit( []( auto const& x )
{ std::cout << "(" << name<decltype(x)>() << ")" << x << std::endl; }, v );
}
int main()
{
std::variant<char, int, float> v1( 1 );
print_variant( "v1", v1 );
std::variant<short, int, double> const v2( 3.14 );
print_variant( "v2", v2 );
auto v3 = rvisit( []( auto const& x, auto const& y ){ return x + y; }, v1, v2 );
print_variant( "v3", v3 );
}
修订历史
1.90.0 版本变更
-
更新了
mp_reverse_fold以支持定长列表
1.88.0 版中的更改
-
修复了
mp_from_sequence的非整数值(由于偏移量支持在 1.83.0 中意外损坏)
1.87.0 版中的更改
-
添加了
mp_lambda(由 Joaquin M Lopez Munoz 贡献)
1.85.0 版本变更
-
添加了
mp_sliding_fold,这是mp_pairwise_fold的泛化(由 Braden Ganetsky 贡献) -
添加了
mp_slice(感谢 Braden Ganetsky) -
为
mp_min_element、mp_max_element添加了值列表支持。 -
为
mp_transform添加了有限的值列表支持。
1.83.0 版的更改
-
为
mp_from_sequence、mp_iota、mp_iota_c添加了偏移量/from 参数。 -
添加了
mp_value、mp_list_v、mp_rename_v、mp_is_value_list。 -
为
<boost/mp11/list.hpp>中的原始函数添加了值列表支持。 -
为
mp_repeat、mp_fill、mp_at、mp_back、mp_take、mp_pop_back、mp_drop、mp_insert、mp_erase添加了值列表支持。
1.79.0 版中的更改
-
添加了
mp_valid_and_true(由 Dmitry Arkhipov 贡献)
1.78.0 版的更改
-
为
mp_compose添加了 n 元函数支持(由 Dmitry Arkhipov 贡献)
1.77.0 版本变更
-
添加了
mp_intersperse、mp_split、mp_join
1.75.0 版本变更
-
添加了
mp_pairwise_fold(由 Barry Revzin 建议) -
移除了
mp_invoke(请使用mp_invoke_q)
1.74.0 版中的更改
-
提高了
mp_with_index<N>对于大的N的编译性能 -
添加了
tuple_transform(由 Hans Dembinski 贡献)
1.73.0 版的更改
-
添加了
mp_unique_if(由 Kris Jusiak 贡献) -
添加了
mp_flatten -
添加了
mp_rotate_left、mp_rotate_right(由 Duncan Barber 贡献) -
添加了
mp_compose -
添加了
mp_power_set -
添加了
mp_partial_sum -
添加了
mp_iterate
1.70.0 版本变更
-
将
mp_invoke重命名为mp_invoke_q -
添加了
mp_similar -
添加了
mp_set_union、mp_set_intersection、mp_set_difference -
添加了
mp_not_fn -
添加了
mp_transform_first、mp_transform_second、mp_transform_third -
添加了
mp_filter -
添加了
mp_eval_if_not、mp_eval_or、mp_valid_q -
添加了
mp_back、mp_pop_back -
添加了
BOOST_MP11_VERSION
1.69.0 版本变更
-
移除了对 Boost.Config 的依赖;Mp11 现在是独立的。
-
改进了
mp_with_index的代码生成 -
添加了
mp_starts_with(由 Glen Fernandes 贡献) -
添加了 CMake 支持
参考
库的内容位于 boost::mp11 命名空间中。
整数常量, <boost/mp11/integral.hpp>
对于 Mp11 整数常量类型 T,T::value 是 C++ 意义上的整数常量。
mp_bool<B>
template<bool B> using mp_bool = std::integral_constant<bool, B>;
与 C++17 中的 std::bool_constant 相同。
mp_true
using mp_true = mp_bool<true>;
与 std::true_type 相同。
mp_false
using mp_false = mp_bool<false>;
与 std::false_type 相同。
mp_to_bool<T>
template<class T> using mp_to_bool = mp_bool<static_cast<bool>(T::value)>;
mp_not<T>
template<class T> using mp_not = mp_bool< !T::value >;
mp_int<I>
template<int I> using mp_int = std::integral_constant<int, I>;
mp_size_t<N>
template<std::size_t N> using mp_size_t = std::integral_constant<std::size_t, N>;
mp_value<A>
template<auto A> using mp_value = std::integral_constant<decltype(A), A>;
当值列表转换为类型列表时,无论是通过 mp_rename 显式转换,还是通过直接支持值列表的原始函数隐式转换,其值都通过 mp_value 包装后转换为类型。
需要 C++17。
列表操作, <boost/mp11/list.hpp>
mp_list<T…>
template<class... T> struct mp_list {};
mp_list 是 Mp11 的标准列表类型,尽管该库并不局限于此,并且可以处理任意类模板,例如 std::tuple 或 std::variant。即使是 std::pair 也可以使用,前提是变换不会改变列表的元素数量。
mp_list_c<T, I…>
template<class T, T... I> using mp_list_c =
mp_list<std::integral_constant<T, I>...>;
mp_list_c 生成一个 mp_list,其元素是对应于其整数模板参数的 std::integral_constant 类型。
using L1 = mp_list_c<int, 2, 3>; // mp_list<mp_int<2>, mp_int<3>>
mp_list_v<A…>
template<auto... A> struct mp_list_v {};
Mp11 的标准值列表类型。需要 C++17。
mp_is_list<L>
template<class L> using mp_is_list = /*...*/;
mp_is_list<L> 如果 L 是一个列表(一个类模板的实例化,其模板参数是类型),则为 mp_true,否则为 mp_false。
mp_is_value_list<L>
template<class L> using mp_is_value_list = /*...*/;
mp_is_value_list<L> 在 C++17 下,如果 L 是一个值列表(一个类模板的实例化,其模板参数全部是值),则为 mp_true,否则为 mp_false。
mp_size<L>
template<class L> using mp_size = /*...*/;
mp_size<L> 返回列表 L 中的元素数量,以 mp_size_t 的形式。换句话说,mp_size<L<T…>> 是 mp_size_t<sizeof…(T)> 的别名。
在 C++17 下支持值列表作为 L。
using L1 = mp_list<>;
using R1 = mp_size<L1>; // mp_size_t<0>
using L2 = std::pair<int, int>;
using R2 = mp_size<L2>; // mp_size_t<2>
using L3 = std::tuple<float>;
using R3 = mp_size<L3>; // mp_size_t<1>
using L4 = mp_list_v<1, false, 8ull>;
using R4 = mp_size<L4>; // mp_size_t<3>
mp_empty<L>
template<class L> using mp_empty = mp_bool<mp_size<L>::value == 0>;
mp_empty<L> 如果列表 L 为空,则为 mp_true 的别名,否则为 mp_false。
在 C++17 下支持值列表作为 L。
using L1 = std::tuple<float>;
using R1 = mp_empty<L1>; // mp_false
using L2 = std::tuple<>;
using R2 = mp_empty<L2>; // mp_true
mp_assign<L1, L2>
template<class L1, class L2> using mp_assign = /*...*/;
mp_assign<L1<T1…>, L2<T2…>> 是 L1<T2…> 的别名。也就是说,它用 L2 的元素替换 L1 的元素。
在 C++17 下支持值列表作为 L1 或 L2。在将值赋给类型时,会用 mp_value 包装它们。在将类型赋给值时,会通过使用 T::value 来解包它们。
using L1 = std::tuple<long>;
using L2 = mp_list<int, float>;
using R1 = mp_assign<L1, L2>; // std::tuple<int, float>
using L1 = std::pair<long, char>;
using L2 = mp_list<int, float>;
using R1 = mp_assign<L1, L2>; // std::pair<int, float>
using L1 = mp_list<int, float>;
using L2 = mp_list_v<0, false>;
using R1 = mp_assign<L1, L2>; // mp_list<mp_int<0>, mp_false>
mp_clear<L>
template<class L> using mp_clear = mp_assign<L, mp_list<>>;
mp_clear<L<T…>> 是 L<> 的别名,也就是说,它会移除 L 的元素。
在 C++17 下支持值列表作为 L。
using L1 = std::tuple<int, float>;
using R1 = mp_clear<L1>; // std::tuple<>
using L1 = mp_list_v<0, true>;
using R1 = mp_clear<L1>; // mp_list_v<>
mp_front<L>
template<class L> using mp_front = /*...*/;
mp_front<L> 是列表 L 的第一个元素。也就是说,mp_front<L<T1, T…>> 是 T1 的别名。
在 C++17 下支持值列表作为 L。在这种情况下,返回的元素会用 mp_value 包装。
using L1 = std::pair<int, float>;
using R1 = mp_front<L1>; // int
using L2 = std::tuple<float, double, long double>;
using R2 = mp_front<L2>; // float
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
using R3 = mp_front<L3>; // char[1]
using L4 = mp_list_v<1, 2, 3, 4>;
using R4 = mp_front<L4>; // mp_int<1>
mp_pop_front<L>
template<class L> using mp_pop_front = /*...*/;
mp_pop_front<L> 移除列表 L 的第一个元素。也就是说,mp_pop_front<L<T1, T…>> 是 L<T…> 的别名。
在 C++17 下支持值列表作为 L。
using L1 = std::tuple<float, double, long double>;
using R1 = mp_pop_front<L1>; // std::tuple<double, long double>
using L2 = mp_list<void>;
using R2 = mp_pop_front<L2>; // mp_list<>
using L3 = mp_list_v<1, 2, 3, 4>;
using R3 = mp_pop_front<L3>; // mp_list_v<2, 3, 4>
mp_first<L>
template<class L> using mp_first = mp_front<L>;
mp_first 是 mp_front 的另一个名称。
mp_rest<L>
template<class L> using mp_rest = mp_pop_front<L>;
mp_rest 是 mp_pop_front 的另一个名称。
mp_second<L>
template<class L> using mp_second = /*...*/;
mp_second<L> 是列表 L 的第二个元素。也就是说,mp_second<L<T1, T2, T…>> 是 T2 的别名。
在 C++17 下支持值列表作为 L。在这种情况下,返回的元素会用 mp_value 包装。
using L1 = std::pair<int, float>;
using R1 = mp_second<L1>; // float
using L2 = std::tuple<float, double, long double>;
using R2 = mp_second<L2>; // double
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
using R3 = mp_second<L3>; // char[2]
using L4 = mp_list_v<1, 2, 3, 4>;
using R4 = mp_second<L4>; // mp_int<2>
mp_third<L>
template<class L> using mp_third = /*...*/;
mp_third<L> 是列表 L 的第三个元素。也就是说,mp_third<L<T1, T2, T3, T…>> 是 T3 的别名。
在 C++17 下支持值列表作为 L。在这种情况下,返回的元素会用 mp_value 包装。
using L1 = std::tuple<float, double, long double>;
using R1 = mp_third<L1>; // long double
using L2 = mp_list<char[1], char[2], char[3], char[4]>;
using R2 = mp_third<L2>; // char[3]
using L3 = mp_list<1, 2, 3, 4>;
using R3 = mp_third<L3>; // mp_int<3>
mp_push_front<L, T…>
template<class L, class... T> using mp_push_front = /*...*/;
mp_push_front<L, T…> 将元素 T… 插入到列表 L 的前面。也就是说,mp_push_front<L<U…>, T…> 是 L<T…, U…> 的别名。
在 C++17 下支持值列表作为 L。在这种情况下,mp_push_front<L<A…>, T…> 是 L<T::value…, A…>。
using L1 = std::tuple<double, long double>;
using R1 = mp_push_front<L1, float>; // std::tuple<float, double, long double>
using L2 = mp_list<void>;
using R2 = mp_push_front<L2, char[1], char[2]>; // mp_list<char[1], char[2], void>
using L3 = mp_list_v<0, 1>;
using R3 = mp_push_front<L3, mp_true, mp_false>; // mp_list_v<true, false, 0, 1>
mp_push_back<L, T…>
template<class L, class... T> using mp_push_back = /*...*/;
mp_push_back<L, T…> 将元素 T… 插入到列表 L 的末尾。也就是说,mp_push_back<L<U…>, T…> 是 L<U…, T…> 的别名。
在 C++17 下支持值列表作为 L。在这种情况下,mp_push_back<L<A…>, T…> 是 L<A…, T::value…>。
using L1 = std::tuple<double, long double>;
using R1 = mp_push_back<L1, float>; // std::tuple<double, long double, float>
using L2 = mp_list<void>;
using R2 = mp_push_back<L2, char[1], char[2]>; // mp_list<void, char[1], char[2]>
using L3 = mp_list_v<0, 1>;
using R3 = mp_push_back<L3, mp_true, mp_false>; // mp_list_v<0, 1, true, false>
mp_rename<L, Y>
template<class L, template<class...> class Y> using mp_rename = /*...*/;
mp_rename<L, Y> 将列表 L 的类型更改为 Y。也就是说,mp_rename<L<T…>, Y> 是 Y<T…> 的别名。
在 C++17 下支持值列表作为 L。在这种情况下,mp_rename<L<A…>, Y> 是 Y<mp_value<A>…>。
using L1 = std::pair<double, long double>;
using R1 = mp_rename<L1, std::tuple>; // std::tuple<double, long double>
using L2 = std::tuple<void>;
using R2 = mp_rename<L2, mp_list>; // mp_list<void>
using L3 = mp_list_v<false, 7>;
using R3 = mp_rename<L3, mp_list>; // mp_list<mp_false, mp_int<7>>
mp_apply<F, L>
template<template<class...> class F, class L> using mp_apply = mp_rename<L, F>;
mp_apply<F, L> 将元函数 F 应用于列表 L 的内容,也就是说,mp_apply<F, L<T…>> 是 F<T…> 的别名。(mp_apply 与参数颠倒的 mp_rename 相同。)
using L1 = std::pair<double, long double>;
using R1 = mp_apply<std::is_same, L1>; // std::is_same<double, long double>
mp_apply_q<Q, L>
template<class Q, class L> using mp_apply_q = mp_apply<Q::template fn, L>;
与 mp_apply 相同,但接受一个引用的元函数。
using L1 = std::tuple<double, long double>;
using L2 = mp_list<int, long>;
using R1 = mp_apply_q<mp_bind_front<mp_push_back, L1>, L2>;
// R1 is std::tuple<double, long double, int, long>
mp_rename_v<L, Y>
template<class L, template<auto...> class Y> using mp_rename_v = /*...*/;
需要 C++17。
对于值列表 L,mp_rename_v<L<A…>, Y> 是 Y<A…>。
对于类型列表 L,mp_rename_v<L<T…>, Y> 是 Y<T::value…> 的别名。
using L1 = mp_list<mp_false, mp_int<7>>;
using R1 = mp_rename_v<L1, mp_list_v>; // mp_list_v<false, 7>;
mp_append<L…>
template<class... L> using mp_append = /*...*/;
mp_append<L…> 将 L… 中的列表连接成一个单一列表,该列表具有与第一个列表相同的类型。mp_append<> 是 mp_list<> 的别名。mp_append<L1<T1…>, L2<T2…>, …, Ln<Tn…>> 是 L1<T1…, T2…, …, Tn…> 的别名。
在 C++17 下支持值列表,但不支持在同一个 mp_append 中混合类型列表和值列表。
using L1 = std::tuple<double, long double>;
using L2 = mp_list<int>;
using L3 = std::pair<short, long>;
using L4 = mp_list<>;
using R1 = mp_append<L1, L2, L3, L4>;
// std::tuple<double, long double, int, short, long>
using L1 = mp_list_v<true, false>;
using L2 = mp_list_v<0, 1, 2, 3>;
using R1 = mp_append<L1, L2>; // mp_list_v<true, false, 0, 1, 2, 3>
mp_replace_front<L, T>
template<class L, class T> using mp_replace_front = /*...*/;
mp_replace_front<L, T> 将列表 L 的第一个元素替换为 T。也就是说,mp_replace_front<L<U1, U…>, T> 是 L<T, U…> 的别名。
在 C++17 下支持值列表作为 L。在这种情况下,mp_replace_front<L<A1, A…>, T> 是 L<T::value, A…>。
using L1 = std::pair<int, float>;
using R1 = mp_replace_front<L1, void>; // std::pair<void, float>
using L2 = std::tuple<float, double, long double>;
using R2 = mp_replace_front<L2, void>; // std::tuple<void, double, long double>
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
using R3 = mp_replace_front<L3, void>; // mp_list<void, char[2], char[3], char[4]>;
using L4 = mp_list_v<1, 2, 3, 4>;
using R4 = mp_replace_front<L4, mp_false>; // mp_list_v<false, 2, 3, 4>;
mp_replace_first<L, T>
template<class L, class T> using mp_replace_first = mp_replace_front<L, T>;
mp_replace_first 是 mp_replace_front 的另一个名称。
mp_replace_second<L, T>
template<class L, class T> using mp_replace_second = /*...*/;
mp_replace_second<L, T> 将列表 L 的第二个元素替换为 T。也就是说,mp_replace_second<L<U1, U2, U…>, T> 是 L<U1, T, U…> 的别名。
在 C++17 下支持值列表作为 L。在这种情况下,mp_replace_second<L<A1, A2, A…>, T> 是 L<A1, T::value, A…>。
using L1 = std::pair<int, float>;
using R1 = mp_replace_second<L1, void>; // std::pair<int, void>
using L2 = std::tuple<float, double, long double>;
using R2 = mp_replace_second<L2, void>; // std::tuple<float, void, long double>
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
using R3 = mp_replace_second<L3, void>; // mp_list<char[1], void, char[3], char[4]>;
using L4 = mp_list_v<1, 2, 3, 4>;
using R4 = mp_replace_second<L4, mp_false>; // mp_list_v<1, false, 3, 4>;
mp_replace_third<L, T>
template<class L, class T> using mp_replace_third = /*...*/;
mp_replace_third<L, T> 将列表 L 的第三个元素替换为 T。也就是说,mp_replace_third<L<U1, U2, U3, U…>, T> 是 L<U1, U2, T, U…> 的别名。
在 C++17 下支持值列表作为 L。在这种情况下,mp_replace_third<L<A1, A2, A3, A…>, T> 是 L<A1, A2, T::value, A…>。
using L1 = std::tuple<float, double, long double>;
using R1 = mp_replace_third<L1, void>; // std::tuple<float, double, void>
using L2 = mp_list<char[1], char[2], char[3], char[4]>;
using R2 = mp_replace_third<L2, void>; // mp_list<char[1], char[2], void, char[4]>;
using L4 = mp_list_v<1, 2, 3, 4>;
using R4 = mp_replace_third<L4, mp_false>; // mp_list_v<1, 2, false, 4>;
mp_transform_front<L, F>
template<class L, template<class...> class F> using mp_transform_front =
/*...*/;
mp_transform_front<L, F> 将列表 L 的第一个元素 T1 替换为 F<T1>。
在 C++17 下支持值列表作为 L。在这种情况下,替换为 F<mp_value<T1>>::value。
mp_transform_front_q<L, Q>
template<class L, class Q> using mp_transform_front_q =
mp_transform_front<L, Q::template fn>;
与 mp_transform_front 相同,但接受一个引用的元函数。
mp_transform_first<L, F>
template<class L, template<class...> class F> using mp_transform_first =
mp_transform_front<L, F>;
mp_transform_first 是 mp_transform_front 的另一个名称。
mp_transform_first_q<L, Q>
template<class L, class Q> using mp_transform_first_q =
mp_transform_first<L, Q::template fn>;
与 mp_transform_first 相同,但接受一个引用的元函数。
mp_transform_second<L, F>
template<class L, template<class...> class F> using mp_transform_second =
/*...*/;
mp_transform_second<L, F> 将列表 L 的第二个元素 T2 替换为 F<T2>。
在 C++17 下支持值列表作为 L。在这种情况下,替换为 F<mp_value<T2>>::value。
mp_transform_second_q<L, Q>
template<class L, class Q> using mp_transform_second_q =
mp_transform_second<L, Q::template fn>;
与 mp_transform_second 相同,但接受一个引用的元函数。
mp_transform_third<L, F>
template<class L, template<class...> class F> using mp_transform_third =
/*...*/;
mp_transform_third<L, F> 将列表 L 的第三个元素 T3 替换为 F<T3>。
在 C++17 下支持值列表作为 L。在这种情况下,替换为 F<mp_value<T3>>::value。
mp_transform_third_q<L, Q>
template<class L, class Q> using mp_transform_third_q =
mp_transform_third<L, Q::template fn>;
与 mp_transform_third 相同,但接受一个引用的元函数。
实用组件, <boost/mp11/utility.hpp>
mp_identity<T>
template<class T> struct mp_identity
{
using type = T;
};
mp_identity 是一个简单的转换类型特征(根据 C++ 标准),它仅返回相同的类型。它既可以单独使用,也可以作为类型包装器,用于将类型作为值传递给函数。
template<class T> using addp_if_not_ref =
typename mp_if<std::is_reference<T>, mp_identity<T>, std::add_pointer<T>>::type;
template<class T> void print1()
{
std::cout << typeid(T).name() << std::endl;
}
template<class T> void print2()
{
std::cout << typeid(mp_identity<T>).name() << std::endl;
}
int main()
{
print1<int const&>(); // 'int'
print2<int const&>(); // 'mp_identity<int const &>'
}
mp_identity_t<T>
template<class T> using mp_identity_t = typename mp_identity<T>::type;
mp_inherit<T…>
template<class... T> struct mp_inherit: T... {};
mp_if_c<C, T, E…>
template<bool C, class T, class... E> using mp_if_c = /*...*/;
mp_if_c<true, T, E…> 是 T 的别名。mp_if_c<false, T, E> 是 E 的别名。否则,结果将是替换失败。
using R1 = mp_if_c<true, int, void>; // int
using R2 = mp_if_c<false, int, void>; // void
template<class I> using void_if_5 = mp_if_c<I::value == 5, void>;
此示例在 I::value 为 5 时返回 void,否则生成替换失败。它相当于 C++14 中的 std::enable_if_t<I::value == 5>,或 C++11 中的 typename std::enable_if<I::value == 5>::type。
mp_if<C, T, E…>
template<class C, class T, class... E> using mp_if =
mp_if_c<static_cast<bool>(C::value), T, E...>;
与 mp_if_c 类似,但第一个参数是类型。
using R1 = mp_if<mp_true, int, void>; // int
using R2 = mp_if<mp_false, int, void>; // void
template<class T> using void_if_const = mp_if<std::is_const<T>, void>;
template<class... T> using void_if_all_const =
mp_if<mp_all<std::is_const<T>...>, void>;
template<class T> using if_non_const = mp_if<mp_not<std::is_const<T>>, T>;
mp_eval_if_c<C, T, F, U…>
template<bool C, class T, template<class...> class F, class... U> using mp_eval_if_c =
/*...*/;
mp_eval_if_c<C, T, F, U…> 在 C 为 true 时是 T 的别名,否则为 F<U…> 的别名。其目的是避免在条件为 true 时评估 F<U…>,因为它在这种情况下可能无效。
template<class... T> using first_or_void =
mp_eval_if_c<sizeof...(T) == 0, void, mp_first, mp_list<T...>>;
mp_eval_if<C, T, F, U…>
template<class C, class T, template<class...> class F, class... U> using mp_eval_if =
mp_eval_if_c<static_cast<bool>(C::value), T, F, U...>;
与 mp_eval_if_c 类似,但第一个参数是类型。
template<class L> using first_or_void = mp_eval_if<mp_empty<L>, void, mp_first, L>;
mp_eval_if_q<C, T, Q, U…>
template<class C, class T, class Q, class... U> using mp_eval_if_q =
mp_eval_if<C, T, Q::template fn, U...>;
与 mp_eval_if 类似,但接受一个引用的元函数。
mp_eval_if_not<C, T, F, U…>
template<class C, class T, template<class...> class F, class... U>
using mp_eval_if_not = mp_eval_if<mp_not<C>, T, F, U...>;
与 mp_eval_if 相同,但条件已反转。
mp_eval_if_not_q<C, T, Q, U…>
template<class C, class T, class Q, class... U> using mp_eval_if_not_q =
mp_eval_if_not<C, T, Q::template fn, U...>;
与 mp_eval_if_not 相同,但接受一个引用的元函数。
mp_valid<F, T…>
template<template<class...> class F, class... T> using mp_valid = /*...*/;
mp_valid<F, T…> 是 mp_true 的别名,当 F<T…> 是一个有效的表达式时;否则为 mp_false。
template<class T> using get_nested_type = typename T::type;
template<class T> struct has_nested_type: mp_valid<get_nested_type, T> {};
mp_valid_q<Q, T…>
template<class Q, class... T> using mp_valid_q = mp_valid<Q::template fn, T...>;
与 mp_valid 类似,但接受一个引用的元函数。
mp_eval_or<T, F, U…>
template<class T, template<class...> class F, class... U> using mp_eval_or =
mp_eval_if_not<mp_valid<F, U...>, T, F, U...>;
mp_eval_or<T, F, U…> 在表达式 F<U…> 有效时是 F<U…> 的别名,否则为 T 的别名。
template<class... T> using first_or_void =
mp_eval_or<void, mp_first, mp_list<T...>>;
mp_eval_or_q<T, Q, U…>
template<class T, class Q, class... U> using mp_eval_or_q =
mp_eval_or<T, Q::template fn, U...>;
与 mp_eval_or 类似,但接受一个引用的元函数。
mp_valid_and_true<F, T…>
template<template<class...> class F, class... T> using mp_valid_and_true =
mp_eval_or<mp_false, F, T...>;
mp_valid_and_true<F, T…> 在表达式 F<T…> 有效时是 F<T…> 的别名,否则为 mp_false 的别名。
mp_valid_and_true_q<Q, T…>
template<class Q, class... T> using mp_valid_and_true_q =
mp_valid_and_true<Q::template fn, T...>;
与 mp_valid_and_true 类似,但接受一个引用的元函数。
mp_cond<C, T, R…>
template<class C, class T, class... R> using mp_cond = /*...*/;
mp_cond<C, T, R…> 在 static_cast<bool>(C::value) 为 true 时是 T 的别名。当 static_cast<bool>(C::value) 为 false 时,它是 mp_cond<R…> 的别名。
(如果 static_cast<bool>(C::value) 是替换失败,结果也将是替换失败。)
template<int N> using unsigned_ = mp_cond<
mp_bool<N == 8>, uint8_t,
mp_bool<N == 16>, uint16_t,
mp_bool<N == 32>, uint32_t,
mp_bool<N == 64>, uint64_t,
mp_true, unsigned // default case
>;
mp_defer<F, T…>
template<template<class...> class F, class... T> using mp_defer = /*...*/;
当 mp_valid<F, T…> 为 mp_true 时,mp_defer<F, T…> 是一个带有嵌套类型 type 的结构体,它是 F<T…> 的别名。否则,mp_defer<F, T…> 是一个空结构体。
mp_quote<F>
template<template<class...> class F> struct mp_quote
{
template<class... T> using fn = F<T...>;
};
mp_quote<F> 将模板 F 转换为一个引用的元函数,一个带有嵌套模板 fn 的类型,使得 fn<T…> 返回 F<T…>。
using LQ = mp_list<mp_quote<std::is_const>, mp_quote<std::is_volatile>>;
mp_quote_trait<F>
template<template<class...> class F> struct mp_quote_trait
{
template<class... T> using fn = typename F<T...>::type;
};
mp_quote_trait<F> 将 C++03 风格的特征 F 转换为一个引用的元函数。
using L1 = mp_list<int, void, float>;
using R1 = mp_transform_q<mp_quote_trait<std::add_pointer>, L1>;
// mp_list<int*, void*, float*>
mp_invoke_q<Q, T…>
template<class Q, class... T> using mp_invoke_q = typename Q::template fn<T...>;
mp_invoke_q<Q, T…> 计算引用的元函数 Q 的嵌套模板 fn。mp_invoke_q<mp_quote<F>, T…> 返回 F<T…>。
using LQ = mp_list<mp_quote<std::is_const>, mp_quote<std::is_volatile>>;
template<class T> using is_const_and_volatile =
mp_apply<mp_all, mp_product<mp_invoke_q, LQ, mp_list<T>>>;
template<class T> using is_const_and_volatile =
mp_apply<mp_all, mp_transform_q<mp_bind_back<mp_invoke_q, T>, LQ>>;
template<class T> using is_const_and_volatile =
mp_apply<mp_all, mp_transform<mp_invoke_q, LQ, mp_fill<LQ, T>>>;
mp_not_fn<P>
template<template<class...> class P> struct mp_not_fn
{
template<class... T> using fn = mp_not<P<T...>>;
};
mp_not_fn<P> 返回一个引用的元函数 Q,使得 Q::fn<T…> 返回 mp_not<P<T…>>。
也就是说,它否定了 P 的结果。
mp_not_fn_q<Q>
template<class Q> using mp_not_fn_q = mp_not_fn<Q::template fn>;
与 mp_not_fn 相同,但接受一个引用的元函数。
mp_compose<F…>
template<template<class...> class... F> struct mp_compose;
mp_compose<F1, F2, …, Fn> 是一个引用的元函数,它按顺序将 F1、F2、…、Fn 应用于其参数。也就是说,mp_compose<F1, F2, …, Fn>::fn<T…> 是 Fn<…F2<F1<T…>>…>。
mp_compose_q<Q…>
template<class... Q> struct mp_compose_q;
与 mp_compose 相同,但接受引用的元函数。
算法, <boost/mp11/algorithm.hpp>
mp_transform<F, L…>
template<template<class...> class F, class... L> using mp_transform = /*...*/;
mp_transform<F, L1<T1…>, L2<T2…>, …, Ln<Tn…>> 将 F 应用于每个连续的元素组,并返回 L1<F<T1, T2, …, Tn>…>。
L… 中的所有列表必须具有相同的大小。否则,结果将是替换失败。
在 C++17 下对值列表作为 L… 提供有限支持(对于一到三个列表)。在这种情况下,元素在传递给 F 之前被 mp_value 包裹,之后被解包。结果是 L1<F<mp_value<T1>, mp_value<T2>, …>::value…>。
template<class T> using add_pointer_t =
typename std::add_pointer<T>::type; // std::add_pointer_t in C++14
using L1 = std::tuple<void, int, float>;
using R1 = mp_transform<add_pointer_t, L1>; // std::tuple<void*, int*, float*>
using L1 = std::tuple<void, int, float>;
using L2 = mp_list<void, int, float>;
using R1 = mp_apply<mp_all, mp_transform<std::is_same, L1, L2>>; // mp_true
template<class T1, class T2> using eq = mp_bool<T1::value == T2::value>;
using L1 = std::tuple<mp_int<1>, mp_int<2>, mp_int<3>>;
using L2 = mp_list<mp_size_t<1>, mp_size_t<2>, mp_size_t<3>>;
using R1 = mp_apply<mp_all, mp_transform<eq, L1, L2>>; // mp_true
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mp_transform_q<Q, L…>
template<class Q, class... L> using mp_transform_q =
mp_transform<Q::template fn, L...>;
与 mp_transform 相同,但接受一个引用的元函数。
void 的出现次数using L1 = std::tuple<void, int, float, void, int>;
using R1 = mp_apply<mp_plus,
mp_transform_q<mp_bind_front<std::is_same, void>, L1>>; // mp_int<2>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mp_transform_if<P, F, L…>
template<template<class...> class P, template<class...> class F, class... L>
using mp_transform_if = /*...*/;
mp_transform_if<P, F, L1, L2, …, Ln> 将列表 L1 中 mp_to_bool<P<T1, T2, …, Tn>> 为 mp_true 的元素替换为 F<T1, T2, …, Tn>,并返回结果,其中 Ti 是 Li 的对应元素。
void 的出现次数替换为第二个列表中对应的元素using L1 = std::tuple<void, int, float, void, int>;
using L2 = std::tuple<char[1], char[2], char[3], char[4], char[5]>;
template<class T1, class T2> using first_is_void = std::is_same<T1, void>;
template<class T1, class T2> using second = T2;
using R1 = mp_transform_if<first_is_void, second, L1, L2>;
// std::tuple<char[1], int, float, char[4], int>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mp_transform_if_q<Qp, Qf, L…>
template<class Qp, class Qf, class... L> using mp_transform_if_q =
mp_transform_if<Qp::template fn, Qf::template fn, L...>;
与 mp_transform_if 相同,但接受引用的元函数。
void 的出现次数替换为第二个列表中对应的元素using L1 = std::tuple<void, int, float, void, int>;
using L2 = std::tuple<char[1], char[2], char[3], char[4], char[5]>;
using R1 = mp_transform_if_q<mp_bind<std::is_same, _1, void>, _2, L1, L2>;
// std::tuple<char[1], int, float, char[4], int>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mp_filter<P, L…>
template<template<class...> class P, class... L> using mp_filter = /*...*/;
mp_filter<P, L1, L2, …, Ln> 移除列表 L1 中 mp_to_bool<P<T1, T2, …, Tn>> 为 mp_false 的元素,并返回结果,其中 Ti 是 Li 的对应元素。
另请参阅 mp_copy_if 和 mp_remove_if,它们是 mp_filter 的不那么通用的变体,只接受单个列表。
mp_filter_q<Qp, L…>
template<class Qp, class... L> using mp_filter_q =
mp_filter<Qp::template fn, L...>;
与 mp_filter 相同,但接受一个引用的元函数。
using L1 = std::tuple<void, int, float>;
using L2 = mp_list<mp_true, mp_false, mp_true>;
using R1 = mp_filter_q<_2, L1, L2>; // std::tuple<void, float>
mp_fill<L, V>
template<class L, class V> using mp_fill = /*...*/;
mp_fill<L<T…>, V> 返回 L<V, V, …, V>,结果的大小与输入相同。
在 C++17 下支持值列表作为 L。在这种情况下,元素被替换为 V::value。
using L1 = std::tuple<void, int, float>;
using R1 = mp_fill<L1, double>; // std::tuple<double, double, double>
using L1 = std::pair<int, float>;
using R1 = mp_fill<L1, void>; // std::pair<void, void>
using L1 = mp_list_v<true, false>;
using R1 = mp_fill<L1, mp_int<7>>; // mp_list_v<7, 7>
|
|
|
|
|
|
|
|
|
|
mp_count<L, V>
template<class L, class V> using mp_count = /*...*/;
mp_count<L, V> 返回 mp_size_t<N>,其中 N 是 L 中与 V 相同的元素数量。
mp_count_if<L, P>
template<class L, template<class...> class P> using mp_count_if = /*...*/;
mp_count_if<L, P> 返回 mp_size_t<N>,其中 N 是 L 中 mp_to_bool<P<T>> 为 mp_true 的元素 T 的数量。
mp_count_if_q<L, Q>
template<class L, class Q> using mp_count_if_q = mp_count_if<L, Q::template fn>;
与 mp_count_if 相同,但接受一个引用的元函数。
mp_contains<L, V>
template<class L, class V> using mp_contains = mp_to_bool<mp_count<L, V>>;
mp_contains<L, V> 当 L 包含元素 V 时为 mp_true,否则为 mp_false。
mp_starts_with<L1, L2>
template<class L1, class L2> using mp_starts_with = /*...*/;
mp_starts_with<L1, L2> 当 L1 以 L2 开头时为 mp_true,否则为 mp_false。
mp_repeat_c<L, N>
template<class L, std::size_t N> using mp_repeat_c = /*...*/;
mp_repeat_c<L, N> 返回一个与 L 相同形式的列表,该列表由 L 的 N 个连接的副本组成。
在 C++17 下支持值列表作为 L。
using L1 = tuple<int>;
using R1 = mp_repeat_c<L1, 3>; // tuple<int, int, int>
using L2 = pair<int, float>;
using R2 = mp_repeat_c<L2, 1>; // pair<int, float>
using L3 = mp_list<int, float>;
using R3 = mp_repeat_c<L3, 2>; // mp_list<int, float, int, float>
using L4 = mp_list<int, float, double>;
using R4 = mp_repeat_c<L4, 0>; // mp_list<>
using L5 = mp_list_v<true, 8>;
using R5 = mp_repeat_c<L5, 2>; // mp_list_v<true, 8, true, 8>
mp_repeat<L, N>
template<class L, class N> using mp_repeat = /*...*/;
与 mp_repeat_c 相同,但有一个类型参数 N。副本数量为 N::value,必须是非负数。
在 C++17 下支持值列表作为 L。
mp_product<F, L…>
template<template<class...> class F, class... L> using mp_product = /*...*/;
mp_product<F, L1<T1…>, L2<T2…>, …, Ln<Tn…>> 为从列表笛卡尔积中获取的值 Ui 计算 F<U1, U2, …, Un>,就好像元素 Ui 是由 n 个嵌套循环形成的,每个循环遍历 Li。它返回一个 L1<V…> 形式的列表,其中包含应用 F 的结果。零个列表的退化情况,mp_product<F>,返回 mp_list<F<>>。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
mp_product_q<Q, L…>
template<class Q, class... L> using mp_product_q = mp_product<Q::template fn, L...>;
与 mp_product 相同,但接受一个引用的元函数。
mp_power_set<L>
template<class L> using mp_power_set = /*...*/;
mp_power_set<L> 返回一个与 L 相同形式的列表,其中包含 L 的所有可能的 2n 个子集(其中 n 是 L 的长度)。
mp_power_set<L<>> 返回 L<L<>>。
mp_power_set<L<T1>> 返回 L<L<>, L<T1>>。
mp_power_set<L<T1, T2>> 返回 L<L<>, L<T2>, L<T1>, L<T1, T2>>。
mp_power_set<L<T1, T…>> 返回 mp_power_set<L<T…>> 与该列表的连接,其中 T1 被添加到每个元素的前面。
mp_drop_c<L, N>
template<class L, std::size_t N> using mp_drop_c = /*...*/;
mp_drop_c<L, N> 移除 L 的前 N 个元素并返回结果。
在 C++17 下支持值列表作为 L。
|
|
|
|
|
|
|
|
|
|
|
|||
mp_drop<L, N>
template<class L, class N> using mp_drop = /*...*/;
与 mp_drop_c 相同,但有一个类型参数 N。N::value 必须是非负数。
mp_from_sequence<S, F>
template<class S, class F = mp_int<0>> using mp_from_sequence = /*...*/
mp_from_sequence 将 make_integer_sequence 生成的整数序列转换为相应的 std::integral_constant 类型的 mp_list。如果提供了可选的第二个参数 F,则会在所有值上加上 F::value 的偏移量。
给定
template<class T, T... I> struct S;
mp_from_sequence<S<T, I…>, F> 是 mp_list<std::integral_constant<T, I + F::value>…> 的别名。
mp_iota_c<N, F>
template<std::size_t N, std::size_t F = 0> using mp_iota_c = /*...*/;
mp_iota_c<N, F> 是 mp_list<mp_size_t<F+0>, mp_size_t<F+1>, …, mp_size_t<F+N-1>> 的别名。
|
|
|
|
|
|
|
|
|
|
mp_iota<N, F>
template<class N, class F = mp_int<0>> using mp_iota = /*...*/;
与 mp_iota_c 相同,但有类型参数 N 和 F。N::value 必须是非负数。返回 mp_list<std::integral_constant<T, F::value+0>, std::integral_constant<T, F::value+1>, …, std::integral_constant<T, F::value+N::value-1>>,其中 T 是 N::value 的类型。
|
|
|
|
|
|
|
|
|
|
mp_at_c<L, I>
template<class L, std::size_t I> using mp_at_c = /*...*/;
mp_at_c<L, I> 返回 L 的第 I 个元素,基于零的索引。
在 C++17 下支持值列表作为 L。在这种情况下,元素以 mp_value 包裹的形式返回。
mp_at<L, I>
template<class L, class I> using mp_at = /*...*/;
与 mp_at_c 相同,但有一个类型参数 I。I::value 必须是非负数。
mp_take_c<L, N>
template<class L, std::size_t N> using mp_take_c = /*...*/;
mp_take_c<L, N> 返回一个与 L 相同形式的列表,其中包含 L 的前 N 个元素。
在 C++17 下支持值列表作为 L。
|
|
|
|
|
|
|
|
|
|
|
|||
mp_take<L, N>
template<class L, class N> using mp_take = /*...*/;
与 mp_take_c 相同,但有一个类型参数 N。N::value 必须是非负数。
mp_slice_c<L, I, J>
template<class L, std::size_t I, std::size_t J> using mp_slice_c = mp_drop_c<mp_take_c<L, J>, I>;
mp_slice_c<L, I, J> 返回一个与 L 相同形式的列表,其中包含从索引 I(包含)到索引 J(排除)的元素。
在 C++17 下支持值列表作为 L。
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
mp_slice<L, I, J>
template<class L, class I, class J> using mp_slice = mp_drop<mp_take<L, J>, I>;
与 mp_slice_c 相同,但有类型参数 I 和 J。I::value 和 J::value 必须是非负数。
mp_back<L>
template<class L> using mp_back = mp_at_c<L, mp_size<L>::value - 1>;
mp_back<L> 返回列表 L 的最后一个元素。
在 C++17 下支持值列表作为 L。在这种情况下,元素以 mp_value 包裹的形式返回。
mp_pop_back<L>
template<class L> using mp_pop_back = mp_take_c<L, mp_size<L>::value - 1>;
mp_pop_back<L> 移除列表 L 的最后一个元素并返回结果。
在 C++17 下支持值列表作为 L。
mp_insert_c<L, I, T…>
template<class L, std::size_t I, class... T> using mp_insert_c =
mp_append<mp_take_c<L, I>, mp_push_front<mp_drop_c<L, I>, T...>>;
将元素 T… 插入到列表 L 的位置 I(零基索引)。
在 C++17 下支持值列表作为 L。在这种情况下,插入的是元素 T::value…。
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
mp_insert<L, I, T…>
template<class L, class I, class... T> using mp_insert =
mp_append<mp_take<L, I>, mp_push_front<mp_drop<L, I>, T...>>;
与 mp_insert_c 相同,但有一个类型参数 I。
mp_erase_c<L, I, J>
template<class L, std::size_t I, std::size_t J> using mp_erase_c =
mp_append<mp_take_c<L, I>, mp_drop_c<L, J>>;
从列表 L 中移除索引从 I(包含)到 J(排除)的元素。
在 C++17 下支持值列表作为 L。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
mp_erase<L, I, J>
template<class L, class I, class J> using mp_erase =
mp_append<mp_take<L, I>, mp_drop<L, J>>;
与 mp_erase_c 相同,但有类型参数 I 和 J。
mp_replace<L, V, W>
template<class L, class V, class W> using mp_replace = /*...*/;
将 L 中的所有 V 元素替换为 W 并返回结果。
|
|
|
|
|
|
|
|
|
|
mp_replace_if<L, P, W>
template<class L, template<class...> class P, class W> using mp_replace_if = /*...*/;
将 L 中所有 mp_to_bool<P<T>> 为 mp_true 的 T 元素替换为 W 并返回结果。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mp_replace_if_q<L, Q, W>
template<class L, class Q, class W> using mp_replace_if_q =
mp_replace_if<L, Q::template fn, W>;
与 mp_replace_if 相同,但接受一个引用的元函数。
mp_replace_at_c<L, I, W>
template<class L, std::size_t I, class W> using mp_replace_at_c = /*...*/;
将 L 中索引为 I(零基)的元素替换为 W 并返回结果。
mp_replace_at<L, I, W>
template<class L, class I, class W> using mp_replace_at = /*...*/;
与 mp_replace_at_c 相同,但有一个类型参数 I。I::value 必须是非负数。
mp_rotate_left_c<L, N>
template<class L, std::size_t N> using mp_rotate_left_c = /*...*/;
将列表 L 的前 N % M 个元素移动到末尾,其中 M 是 L 的大小。空列表保持不变。
mp_rotate_left<L, N>
template<class L, class N> using mp_rotate_left = /*...*/;
与 mp_rotate_left_c 相同,但有一个类型参数 N。N::value 必须是非负数。
mp_rotate_right_c<L, N>
template<class L, std::size_t N> using mp_rotate_right_c = /*...*/;
将列表 L 的后 N % M 个元素移动到开头,其中 M 是 L 的大小。空列表保持不变。
mp_rotate_right<L, N>
template<class L, class N> using mp_rotate_right = /*...*/;
与 mp_rotate_right_c 相同,但有一个类型参数 N。N::value 必须是非负数。
mp_copy_if<L, P>
template<class L, template<class...> class P> using mp_copy_if = /*...*/;
将 L 中 mp_to_bool<P<T>> 为 mp_true 的元素 T 复制到一个新列表中(形式与 L 相同)并返回它。
mp_copy_if_q<L, Q>
template<class L, class Q> using mp_copy_if_q = mp_copy_if<L, Q::template fn>;
与 mp_copy_if 相同,但接受一个引用的元函数。
mp_remove<L, V>
template<class L, class V> using mp_remove = /*...*/;
移除 L 中的所有 V 元素并返回结果。
mp_remove_if<L, P>
template<class L, template<class...> class P> using mp_remove_if = /*...*/;
移除 L 中所有 mp_to_bool<P<T>> 为 mp_true 的元素 T 并返回结果。
mp_remove_if_q<L, Q>
template<class L, class Q> using mp_remove_if_q = mp_remove_if<L, Q::template fn>;
与 mp_remove_if 相同,但接受一个引用的元函数。
mp_flatten<L>
template<class L, class L2 = mp_clear<L>> using mp_flatten = /*...*/;
将 L 中所有与 L2 相同形式的列表(即 mp_similar<T, L2> 为 mp_true 的列表)的元素替换为它们的元素,并返回结果。
using L1 = tuple<int, tuple<>, void, tuple<float, double>>;
using R1 = mp_flatten<L1>; // tuple<int, void, float, double>
using L2 = mp_list<int, mp_list<float>, tuple<void>>;
using R2a = mp_flatten<L2>; // mp_list<int, float, tuple<void>>
using R2b = mp_flatten<L2, tuple<>>; // mp_list<int, mp_list<float>, void>
using L3 = mp_list<mp_list<float>, mp_list<mp_list<void>>>;
using R3 = mp_flatten<L3>; // mp_list<float, mp_list<void>>
mp_intersperse<L, S>
template<class L, class S> using mp_intersperse = /*...*/;
在列表 L 的元素之间插入分隔符 S。
mp_intersperse<L<>, S> 是 L<>。mp_intersperse<L<T1>, S> 是 L<T1>。mp_intersperse<L<T1, T2, T3, …, Tn-1, Tn>, S> 是 L<T1, S, T2, S, T3, S, …, Tn-1, S, Tn>。
mp_split<L, S>
template<class L, class S> using mp_split = /*...*/;
在每个分隔符 S 处将列表 L 分割成段,并返回段列表。
mp_split<L<>, S> 是 L<L<>>。mp_split<L<T…>, S>,其中 S 不出现在 T… 中,是 L<L<T…>>。mp_split<L<T1…, S, T2…, S, T3…>, S> 是 L<L<T1…>, L<T2…>, L<T3…>>。
段可以为空;mp_split<L<S, X, Y, S, S>, S> 是 L<L<>, L<X, Y>, L<>, L<>>。
mp_join<L, S>
template<class L, class S> using mp_join = /*...*/;
mp_join 是 mp_split 的反向操作;它接受一个段列表 L,并在它们之间插入分隔符 S,将它们连接成一个单一列表。
mp_join<mp_split<L, S>, S> 会恢复原始列表 L。
例如,mp_split<L<X1, X2, S, X3>, S> 给出 L<L<X1, X2>, L<X3>>,而 mp_join<L<L<X1, X2>, L<X3>>, S> 结果为 L<X1, X2, S, X3>。
mp_join<L, S> 等同于(并且实现为)mp_apply<mp_append, mp_intersperse<L, mp_list<S>>>。
mp_partition<L, P>
template<class L, template<class...> class P> using mp_partition = /*...*/;
mp_partition<L<T…>, P> 将 L 分成两个列表 L<U1…> 和 L<U2…>,使得 mp_to_bool<P<T>> 对于 L<U1…> 的元素为 mp_true,对于 L<U2…> 的元素为 mp_false。返回 L<L<U1…>, L<U2…>>。
mp_partition_q<L, Q>
template<class L, class Q> using mp_partition_q = mp_partition<L, Q::template fn>;
与 mp_partition 相同,但接受一个引用的元函数。
mp_sort<L, P>
template<class L, template<class...> class P> using mp_sort = /*...*/;
mp_sort<L, P> 根据严格弱序 mp_to_bool<P<T, U>> 对列表 L 进行排序。
#include <ratio>
using L1 = mp_list<std::ratio<1,2>, std::ratio<1,4>>;
using R1 = mp_sort<L1, std::ratio_less>; // mp_list<ratio<1,4>, ratio<1,2>>
mp_sort_q<L, Q>
template<class L, class Q> using mp_sort_q = mp_sort<L, Q::template fn>;
与 mp_sort 相同,但接受一个引用的元函数。
mp_nth_element_c<L, I, P>
template<class L, std::size_t I, template<class...> class P> using mp_nth_element_c =
/*...*/;
返回 mp_sort<L, P> 中位置为 I 的元素。
mp_nth_element<L, I, P>
template<class L, class I, template<class...> class P> using mp_nth_element = /*...*/;
类似于 mp_nth_element_c,但有一个类型参数 I。I::value 必须是非负数。
mp_nth_element_q<L, I, Q>
template<class L, class I, class Q> using mp_nth_element_q =
mp_nth_element<L, I, Q::template fn>;
类似于 mp_nth_element,但接受一个引用的元函数。
mp_min_element<L, P>
template<class L, template<class...> class P> using mp_min_element = /*...*/;
mp_min_element<L, P> 根据序 mp_to_bool<P<T, U>> 返回列表 L 的最小元素。
它等同于 mp_fold<mp_rest<L>, mp_first<L>, F>,其中 F<T, U> 返回 mp_if<P<T, U>, T, U>。
在 C++17 下支持值列表作为 L。在这种情况下,元素以 mp_value 包裹的形式返回。
mp_min_element_q<L, Q>
template<class L, class Q> using mp_min_element_q = mp_min_element<L, Q::template fn>;
与 mp_min_element 相同,但接受一个引用的元函数。
mp_max_element<L, P>
template<class L, template<class...> class P> using mp_max_element = /*...*/;
mp_max_element<L, P> 根据序 mp_to_bool<P<T, U>> 返回列表 L 的最大元素。
它等同于 mp_fold<mp_rest<L>, mp_first<L>, F>,其中 F<T, U> 返回 mp_if<P<U, T>, T, U>。
在 C++17 下支持值列表作为 L。在这种情况下,元素以 mp_value 包裹的形式返回。
mp_max_element_q<L, Q>
template<class L, class Q> using mp_max_element_q = mp_max_element<L, Q::template fn>;
与 mp_max_element 相同,但接受一个引用的元函数。
mp_find<L, V>
template<class L, class V> using mp_find = /*...*/;
mp_find<L, V> 返回类型 V 在列表 L 中出现的位置索引。它是 mp_size_t<I> 的别名,其中 I 是 L 中 V 首次出现时的零基索引。如果 L 不包含 V,mp_find<L, V> 是 mp_size<L>。
mp_find_if<L, P>
template<class L, template<class...> class P> using mp_find_if = /*...*/;
mp_find_f<L, P> 是 mp_size_t<I> 的别名,其中 I 是 L 中第一个元素 T 满足 mp_to_bool<P<T>> 为 mp_true 的零基索引。如果不存在这样的元素,mp_find_if<L, P> 是 mp_size<L>。
mp_find_if_q<L, Q>
template<class L, class Q> using mp_find_if_q = mp_find_if<L, Q::template fn>;
与 mp_find_if 相同,但接受一个引用的元函数。
mp_reverse<L>
template<class L> using mp_reverse = /*...*/;
mp_reverse<L<T1, T2, …, Tn>> 是 L<Tn, …, T2, T1>。
|
|
|
|
|
|
|
|
|
|
mp_fold<L, V, F>
template<class L, class V, template<class...> class F> using mp_fold = /*...*/;
mp_fold<L<T1, T2, …, Tn>, V, F> 是 F< F< F< F<V, T1>, T2>, …>, Tn>,如果 L 为空,则为 V。
#include <ratio>
using L1 = mp_list<std::ratio<1,8>, std::ratio<1,4>, std::ratio<1,2>>;
using R1 = mp_fold<L1, std::ratio<0,1>, std::ratio_add>; // std::ratio<7,8>
mp_fold_q<L, V, Q>
template<class L, class V, class Q> using mp_fold_q =
mp_fold<L, V, Q::template fn>;
与 mp_fold 相同,但接受一个引用的元函数。
mp_reverse_fold<L, V, F>
template<class L, class V, template<class...> class F> using mp_reverse_fold =
/*...*/;
mp_reverse_fold<L<T1, T2, …, Tn>, V, F> 是 F<T1, F<T2, F<…, F<Tn, V>>>>,如果 L 为空,则为 V。
mp_reverse_fold_q<L, V, Q>
template<class L, class V, class Q> using mp_reverse_fold_q =
mp_reverse_fold<L, V, Q::template fn>;
与 mp_reverse_fold 相同,但接受一个引用的元函数。
mp_partial_sum<L, V, F>
template<class L, class V, template<class...> class F> using mp_partial_sum = /*...*/;
mp_partial_sum<L, V, F> 类似于 mp_fold<L, V, F>,但它不返回最终结果,而是返回一个列表(形式与 L 相同),其中包含折叠的中间结果。mp_partial_sum 结果的最后一个元素与 mp_fold 的结果相同。
例如,mp_fold<mp_list<X1, X2, X3>, V, F> 是 F<F<F<V, X1>, X2>, X3>,但 mp_partial_sum<mp_list<X1, X2, X3>, V, F> 是 mp_list<F<V, X1>, F<F<V, X1>, X2>, F<F<F<V, X1>, X2>, X3>>。
F 通常是 mp_plus,在这种情况下,结果包含 L 的部分和。
using L1 = mp_list_c<int, 1, 2, 3, 4>;
using R1 = mp_partial_sum<L1, mp_int<0>, mp_plus>; // mp_list_c<int, 1, 3, 6, 10>
mp_partial_sum_q<L, V, Q>
template<class L, class V, class Q> using mp_partial_sum_q =
mp_partial_sum<L, V, Q::template fn>;
与 mp_partial_sum 相同,但接受一个引用的元函数。
mp_pairwise_fold<L, F>
template<class L, template<class...> class F> using mp_pairwise_fold = /*...*/;
mp_pairwise_fold<L, F> 返回一个与 L 相同形式的列表,其元素是通过将二元元函数 F 应用于 L 的每对相邻元素的结果。也就是说,mp_pairwise_fold<L<T1, T2, T3>, F> 是 L<F<T1, T2>, F<T2, T3>>。
结果的元素比原始列表少一个。如果 L 只有一个元素,则结果是一个空列表。如果 L 是一个空列表,结果也是一个空列表。
template<class L> using is_increasing = mp_all_of<
mp_pairwise_fold<L, mp_less>, mp_to_bool>;
mp_pairwise_fold_q<L, Q>
template<class L, class Q> using mp_pairwise_fold_q =
mp_pairwise_fold<L, Q::template fn>;
与 mp_pairwise_fold 相同,但接受一个引用的元函数。
template<class L, template<class...> class P> using is_sorted =
mp_none_of<mp_pairwise_fold_q<L, mp_bind<P, _2, _1>>, mp_to_bool>;
mp_sliding_fold<L, N, F>
template<class L, class N, template<class...> class F> using mp_sliding_fold = /*...*/;
mp_sliding_fold<L, N, F> 返回一个与 L 相同形式的列表,其元素是通过将 n 元元函数 F 应用于 L 的每个 n 元相邻元素组的结果。也就是说,mp_sliding_fold<L<T1, T2, T3, T4>, mp_size_t<3>, F> 是 L<F<T1, T2, T3>, F<T2, T3, T4>>。
结果比原始列表少 N-1 个元素。如果 L 的元素少于 N::value,则结果为空列表。
template<class L, class N> using local_maximum =
mp_sliding_fold<L, N, mp_max>;
mp_sliding_fold_q<L, N, Q>
template<class L, class N, class Q> using mp_sliding_fold_q =
mp_sliding_fold<L, N, Q::template fn>;
与 mp_sliding_fold 相同,但接受一个引用的元函数。
struct average { template<class... C> using fn = mp_int<mp_plus<C...>::value / sizeof...(C)>; };
template<class L, class N> using moving_average =
mp_sliding_fold_q<L, N, average>;
mp_iterate<V, F, R>
template<class V, template<class...> class F, template<class...> class R>
using mp_iterate = /*...*/;
mp_iterate<V, F, R> 连续地将 R 应用于 V,直到不再可能,生成序列 V、R<V>、R<R<V>>、R<R<R<V>>>…
然后它返回一个 mp_list,其元素是通过将 F 应用于上述值序列形成的。也就是说,它返回 mp_list<F<V>, F<R<V>>, F<R<R<V>>>, …>。
mp_iterate 在某种程度上是 mp_reverse_fold 的反向操作。给定
template<class T, class U> struct cons {};
struct nil {};
mp_reverse_fold<mp_list<X1, X2, X3>, nil, cons> 生成 cons<X1, cons<X2, cons<X3, nil>>>,当作为 V 传递给 mp_iterate<V, mp_first, mp_second> 时,会恢复原始的 mp_list<X1, X2, X3>。
struct X1 {};
struct X2 {};
struct X3 {};
using L1 = mp_list<X1, X2, X3>;
using R1 = mp_iterate<L1, mp_first, mp_rest>; // L1
template<class T, class U> struct cons {};
struct nil {};
using V2 = mp_reverse_fold<L1, nil, cons>; // cons<X1, cons<X2, cons<X3, nil>>>
using R2 = mp_iterate<V2, mp_first, mp_second>; // L1
struct Y1 {};
struct Y2 { using value_type = double; using next_type = Y1; };
struct Y3 { using value_type = float; using next_type = Y2; };
struct Y4 { using value_type = int; using next_type = Y3; };
template<class T> using value_type = typename T::value_type;
template<class T> using next_type = typename T::next_type;
using R3 = mp_iterate<Y4, mp_identity_t, next_type>; // mp_list<Y4, Y3, Y2, Y1>
using R4 = mp_iterate<Y4, value_type, next_type>; // mp_list<int, float, double>
mp_iterate_q<V, Qf, Qr>
template<class V, class Qf, class Qr> using mp_iterate_q =
mp_iterate<V, Qf::template fn, Qr::template fn>;
与 mp_iterate 相同,但接受引用的元函数。
mp_unique<L>
template<class L> using mp_unique = /*...*/;
mp_unique<L> 返回一个与 L 相同形式的列表,并移除了重复的元素。
mp_unique_if<L, P>
template<class L, template<class...> class P> using mp_unique_if = /*...*/;
与 mp_unique 相同,但当 mp_to_bool<P<T, U>> 为 mp_true 时,两个元素 T 和 U 被视为重复项。
mp_unique_if_q<L, Q>
template<class L, class Q> using mp_unique_if_q =
mp_unique_if<L, Q::template fn>;
与 mp_unique_if 相同,但接受一个引用的元函数。
mp_all_of<L, P>
template<class L, template<class...> class P> using mp_all_of =
mp_bool< mp_count_if<L, P>::value == mp_size<L>::value >;
mp_all_of<L, P> 当 P 对 L 的所有元素都成立时为 mp_true,否则为 mp_false。当 L 为空时,结果为 mp_true。
mp_all_of_q<L, Q>
template<class L, class Q> using mp_all_of_q = mp_all_of<L, Q::template fn>;
与 mp_all_of 相同,但接受一个引用的元函数。
mp_none_of<L, P>
template<class L, template<class...> class P> using mp_none_of =
mp_bool< mp_count_if<L, P>::value == 0 >;
mp_none_of<L, P> 当 P 对 L 的任何元素都不成立时为 mp_true,否则为 mp_false。当 L 为空时,结果为 mp_true。
mp_none_of_q<L, Q>
template<class L, class Q> using mp_none_of_q = mp_none_of<L, Q::template fn>;
与 mp_none_of 相同,但接受一个引用的元函数。
mp_any_of<L, P>
template<class L, template<class...> class P> using mp_any_of =
mp_bool< mp_count_if<L, P>::value != 0 >;
mp_any_of<L, P> 当 P 对 L 的至少一个元素成立时为 mp_true,否则为 mp_false。当 L 为空时,结果为 mp_false。
mp_any_of_q<L, Q>
template<class L, class Q> using mp_any_of_q = mp_any_of<L, Q::template fn>;
与 mp_any_of 相同,但接受一个引用的元函数。
mp_for_each<L>(f)
template<class L, class F> constexpr F mp_for_each(F&& f);
mp_for_each<L>(f) 按顺序用 T() 调用 f,对于列表 L 中的每个元素 T。
返回 std::forward<F>(f)。
template<class... T> void print( std::tuple<T...> const & tp )
{
std::size_t const N = sizeof...(T);
mp_for_each<mp_iota_c<N>>( [&]( auto I ){
// I is mp_size_t<0>, mp_size_t<1>, ..., mp_size_t<N-1>
std::cout << std::get<I>(tp) << std::endl;
});
}
如果列表 L 的元素不是默认可构造的,则可以使用 mp_for_each<mp_transform<mp_identity, L>>,它会用 mp_identity<T>() 而不是 T() 调用 f。
mp_with_index<N>(i, f)
template<std::size_t N, class F>
constexpr auto mp_with_index( std::size_t i, F && f )
-> decltype(std::declval<F>()(std::declval<mp_size_t<0>>()));
mp_with_index<N>(i, f) 用 mp_size_t<i>() 调用 f 并返回结果。i 必须小于 N。仅在 C++14 及更高版本中为 constexpr。
template<class N, class F>
constexpr auto mp_with_index( std::size_t i, F && f )
-> decltype(std::declval<F>()(std::declval<mp_size_t<0>>()));
返回 mp_with_index<N::value>(i, f)。
template<class... T> void print( std::variant<T...> const& v )
{
mp_with_index<sizeof...(T)>( v.index(), [&]( auto I ) {
// I is mp_size_t<v.index()>{} here
std::cout << std::get<I>( v ) << std::endl;
});
}
集合操作, <boost/mp11/set.hpp>
集合是元素唯一的列表。
mp_is_set<S>
template<class S> using mp_is_set = /*...*/;
mp_is_set<S> 如果 S 是一个集合,则为 mp_true,否则为 mp_false。
mp_set_contains<S, V>
template<class S, class V> using mp_set_contains = /*...*/;
mp_set_contains<S, V> 如果类型 V 是集合 S 的元素,则为 mp_true,否则为 mp_false。
mp_set_push_back<S, T…>
template<class S, class... T> using mp_set_push_back = /*...*/;
对于 T1 在 T… 中的每个元素,如果 T1 尚不存在于集合 S 中,则 mp_set_push_back<S, T…> 将 T1 追加到集合 S 的末尾。
mp_set_push_front<S, T…>
template<class S, class... T> using mp_set_push_front = /*...*/;
mp_set_push_front<S, T…> 将 T… 中 S 不包含相同类型的元素插入到集合 S 的开头。
mp_set_union<L…>
template<class... L> using mp_set_union = /*...*/;
mp_set_union<S, L…> 是 mp_set_push_back<S, T…>,其中 T… 是列表 L… 的组合元素。mp_set_union<> 是 mp_list<>。
mp_set_intersection<S…>
template<class... S> using mp_set_intersection = /*...*/;
mp_set_intersection<S…> 返回一个包含所有集合 S… 中出现的元素的集合。mp_set_intersection<> 是 mp_list<>。
mp_set_difference<L, S…>
template<class L, class... S> using mp_set_difference = /*...*/;
mp_set_difference<L, S…> 移除列表 L 中出现在任何集合 S… 中的元素并返回结果。
映射操作, <boost/mp11/map.hpp>
映射是列表的列表,内部列表至少包含一个元素(键)。映射的键必须是唯一的。
mp_is_map<M>
template<class M> using mp_is_map = /*...*/;
mp_is_map<M> 如果 M 是一个映射,则为 mp_true,否则为 mp_false。
mp_map_find<M, K>
template<class M, class K> using mp_map_find = /*...*/;
mp_map_find<M, K> 是映射 M 中键为 K 的元素的别名,如果没有这样的元素,则为 void 的别名。
mp_map_contains<M, K>
template<class M, class K> using mp_map_contains =
mp_not<std::is_same<mp_map_find<M, K>, void>>;
mp_map_contains<M, K> 如果映射 M 包含键为 K 的元素,则为 mp_true,否则为 mp_false。
mp_map_insert<M, T>
template<class M, class T> using mp_map_insert =
mp_if< mp_map_contains<M, mp_first<T>>, M, mp_push_back<M, T> >;
如果映射 M 中不存在键为 mp_first<T> 的元素,则将元素 T 插入到映射 M 中。
mp_map_replace<M, T>
template<class M, class T> using mp_map_replace = /*...*/;
如果映射 M 中不存在键为 mp_first<T> 的元素,则将其插入(使用 mp_push_back<M, T>);否则,用 T 替换现有元素。
mp_map_update<M, T, F>
template<class M, class T, template<class...> class F> using mp_map_update = /*...*/;
如果映射 M 中不存在键为 mp_first<T> 的元素,则将其插入(使用 mp_push_back<M, T>);否则,用 L<X, F<X, Y…>> 替换现有元素 L<X, Y…>。
template<class T, class U> using inc2nd = mp_int<U::value + 1>;
template<class M, class T> using count_types =
mp_map_update<M, std::pair<T, mp_int<1>>, inc2nd>;
using L1 = mp_list<float, char, float, float, float, float, char, float>;
using R1 = mp_fold<L1, std::tuple<>, count_types>;
// std::tuple<std::pair<float, mp_int<6>>, std::pair<char, mp_int<2>>>
mp_map_update_q<M, T, Q>
template<class M, class T, class Q> using mp_map_update_q =
mp_map_update<M, T, Q::template fn>;
与 mp_map_update 类似,但接受一个带引号的元函数。
mp_map_erase<M, K>
template<class M, class K> using mp_map_erase = /*...*/;
如果映射 M 包含一个键为 K 的元素,则将其移除。
mp_map_keys<M>
template<class M> using mp_map_keys = mp_transform<mp_first, M>;
mp_map_keys<M> 返回 M 的键列表。当 M 是一个有效的映射时,键是唯一的,因此结果是一个集合。
辅助元函数, <boost/mp11/function.hpp>
mp_void<T…>
template<class... T> using mp_void = void;
与 C++17 的 std::void_t 相同。
mp_and<T…>
template<class... T> using mp_and = /*...*/;
mp_and<T…> 按顺序将 mp_to_bool 应用于 T… 中的类型。如果应用结果是 mp_false,则 mp_and 返回 mp_false。如果应用导致替换失败,则返回 mp_false。如果所有结果都是 mp_true,则返回 mp_true。mp_and<> 是 mp_true。
using R1 = mp_and<mp_true, mp_true>; // mp_true
using R2 = mp_and<mp_false, void>; // mp_false, void is not reached
using R3 = mp_and<mp_false, mp_false>; // mp_false
using R4 = mp_and<void, mp_true>; // mp_false (!)
mp_all<T…>
template<class... T> using mp_all = /*...*/;
如果 T… 中的所有类型 U 的 mp_to_bool<U> 都为 mp_true,则 mp_all<T…> 为 mp_true,否则为 mp_false。与 mp_and 相同,但不执行短路求值。mp_and<mp_false, void> 为 mp_false,但 mp_all<mp_false, void> 是一个错误,因为 void 没有嵌套的 value。优点是 mp_all 可能更快,并且不像 mp_and 那样会掩盖替换失败。
using R1 = mp_all<mp_true, mp_true>; // mp_true
using R2 = mp_all<mp_false, void>; // compile-time error
using R3 = mp_all<mp_false, mp_false>; // mp_false
using R4 = mp_all<void, mp_true>; // compile-time error
mp_or<T…>
template<class... T> using mp_or = /*...*/;
mp_or<T…> 按顺序将 mp_to_bool 应用于 T… 中的类型。如果应用结果是 mp_true,则 mp_or 返回 mp_true。如果所有结果都是 mp_false,则返回 mp_false。mp_or<> 是 mp_false。
using R1 = mp_or<mp_true, mp_false>; // mp_true
using R2 = mp_or<mp_true, void>; // mp_true, void is not reached
using R3 = mp_or<mp_false, mp_false>; // mp_false
using R4 = mp_or<void, mp_true>; // compile-time error
mp_any<T…>
template<class... T> using mp_any = /*...*/;
如果 T… 中的任何类型 U 的 mp_to_bool<U> 为 mp_true,则 mp_any<T…> 为 mp_true,否则为 mp_false。与 mp_or 相同,但不执行短路求值。
using R1 = mp_any<mp_true, mp_false>; // mp_true
using R2 = mp_any<mp_true, void>; // compile-time error
using R3 = mp_any<mp_false, mp_false>; // mp_false
using R4 = mp_any<void, mp_true>; // compile-time error
mp_same<T…>
template<class... T> using mp_same = /*...*/;
如果 T… 中的所有类型都相同,则 mp_same<T…> 为 mp_true,否则为 mp_false。mp_same<> 为 mp_true。
mp_similar<T…>
template<class... T> using mp_similar = /*...*/;
如果 T… 中的所有类型都相同,或者都是相同类模板的实例化,并且所有模板参数都是类型,则 mp_similar<T…> 为 mp_true,否则为 mp_false。mp_similar<> 为 mp_true。
using R1 = mp_similar<void>; // mp_true
using R2 = mp_similar<void, void>; // mp_true
using R3 = mp_similar<void, void, void>; // mp_true
using R4 = mp_similar<void, void, float>; // mp_false
template<class T> struct X;
template<class... T> struct Y;
using R5 = mp_similar<X<int>, X<void>, X<float>>; // mp_true
using R6 = mp_similar<Y<>, Y<void>, Y<void, void>>; // mp_true
using R7 = mp_similar<X<void>, Y<void>>; // mp_false
mp_plus<T…>
template<class... T> using mp_plus = /*...*/;
mp_plus<T…> 是一个整型常量类型,其值为 T… 中所有类型 U 的 U::value 之和。mp_plus<> 是 mp_int<0>。
mp_less<T1, T2>
template<class T1, class T2> using mp_less = /*...*/;
当 T1::value 的数值小于 T2::value 的数值时,mp_less<T1, T2> 为 mp_true,否则为 mp_false。
(请注意,在比较有符号和无符号类型时,这不一定与 T1::value < T2::value 相同;-1 < 1u 为 false,但 mp_less<mp_int<-1>, mp_size_t<1>> 为 mp_true。)
mp_min<T1, T…>
template<class T1, class... T> using mp_min = mp_min_element<mp_list<T1, T...>, mp_less>;
mp_min<T…> 返回 T… 中 U::value 最小的类型 U。
mp_max<T1, T…>
template<class T1, class... T> using mp_max = mp_max_element<mp_list<T1, T...>, mp_less>;
mp_max<T…> 返回 T… 中 U::value 最大的类型 U。
绑定, <boost/mp11/bind.hpp>
mp_arg<I>
template<std::size_t I> struct mp_arg;
mp_arg<I> 是一个带引号的元函数,其嵌套模板 fn<T…> 返回 T… 的第 I 个(从零开始)元素。
_1, …, _9
using _1 = mp_arg<0>; using _2 = mp_arg<1>; using _3 = mp_arg<2>; using _4 = mp_arg<3>; using _5 = mp_arg<4>; using _6 = mp_arg<5>; using _7 = mp_arg<6>; using _8 = mp_arg<7>; using _9 = mp_arg<8>;
_1 到 _9 是占位符类型,等同于 boost::bind 的占位符。
mp_bind<F, T…>
template<template<class...> class F, class... T> struct mp_bind;
mp_bind<F, T…> 是一个带引号的元函数,它实现了 boost::bind 的类型等价。其嵌套模板 fn<U…> 返回 F<V…>,其中 V… 是 T… 中用 U… 的对应元素替换占位符的结果,并且 mp_bind、mp_bind_front 和 mp_bind_back 表达式被替换为它们针对 U… 的相应求值结果。
例如,mp_bind<F, int, _2, mp_bind<G, _1>>::fn<float, void> 等同于 F<int, void, G<float>>。
mp_bind_q<Q, T…>
template<class Q, class... T> using mp_bind_q = mp_bind<Q::template fn, T...>;
与 mp_bind 类似,但接受一个带引号的元函数。
mp_bind_front<F, T…>
template<template<class...> class F, class... T> struct mp_bind_front;
mp_bind_front<F, T…> 将 F 的最左侧参数绑定到 T…。其嵌套模板 fn<U…> 返回 F<T…, U…>。
mp_bind_front_q<Q, T…>
template<class Q, class... T> using mp_bind_front_q =
mp_bind_front<Q::template fn, T...>;
与 mp_bind_front 类似,但接受一个带引号的元函数。
mp_bind_back<F, T…>
template<template<class...> class F, class... T> struct mp_bind_back;
mp_bind_back<F, T…> 将 F 的最右侧参数绑定到 T…。其嵌套模板 fn<U…> 返回 F<U…, T…>。
mp_bind_back_q<Q, T…>
template<class Q, class... T> using mp_bind_back_q =
mp_bind_back<Q::template fn, T...>;
与 mp_bind_back 类似,但接受一个带引号的元函数。
Lambda 表达式, <boost/mp11/lambda.hpp>
mp_lambda<T>
template<class T> using mp_lambda = /*...*/;
mp_lambda<T> 是一个带引号的元函数,其嵌套模板 fn<U…> 返回一个类型 V,该类型与 T 具有相同的语法定义,只是 T 中的占位符被 U… 的对应元素替换。
例如,mp_lambda<std::pair<_1, _2*>>::fn<int, char> 等同于 std::pair<int, char*>。
替换不会发生在 T 的那些由于使用非类型模板参数实例化类模板而产生的组成部分内部。
|
注意
|
在 GCC 4.8 中,一个编译器 bug 导致返回类型 V 中的 const 和 volatile 限定符被剥离(除非它们应用于函数或成员函数类型)。 |
|
注意
|
由于编译器限制,VS2013 及更早版本不支持 mp_lambda。 |
整数序列, <boost/mp11/integer_sequence.hpp>
integer_sequence<T, I…>
template<class T, T... I> struct integer_sequence
{
};
integer_sequence<T, I…> 保存一个类型为 T 的整数序列。与 C++14 的 std::integer_sequence 相同。
make_integer_sequence<T, N>
template<class T, T N> using make_integer_sequence = /*...*/;
make_integer_sequence<T, N> 是 integer_sequence<T, 0, 1, …, N-1>。与 C++14 的 std::make_integer_sequence 相同。
index_sequence<I…>
template<std::size_t... I> using index_sequence = integer_sequence<std::size_t, I...>;
index_sequence<I…> 是 integer_sequence<size_t, I…> 的别名。与 C++14 的 std::index_sequence 相同。
make_index_sequence<N>
template<std::size_t N> using make_index_sequence =
make_integer_sequence<std::size_t, N>;
make_index_sequence<N> 是 index_sequence<0, 1, …, N-1>。与 C++14 的 std::make_index_sequence 相同。
index_sequence_for<T…>
template<class... T> using index_sequence_for =
make_integer_sequence<std::size_t, sizeof...(T)>;
index_sequence_for<N> 是 make_index_sequence<sizeof…(T)>。与 C++14 的 std::index_sequence_for 相同。
Tuple 操作, <boost/mp11/tuple.hpp>
tuple_apply(f, tp)
template<class F, class Tp> constexpr /*...*/ tuple_apply(F&& f, Tp&& tp);
tuple_apply(f, tp) 对 J 从 0 到 N-1(其中 N 是 std::tuple_size<typename std::remove_reference<Tp>::type>::value)返回 std::forward<F>(f)(std::get<J>(std::forward<Tp>(tp))…)。与 C++17 的 std::apply 相同。
construct_from_tuple<T>(tp)
template<class T, class Tp> T construct_from_tuple(Tp&& tp);
construct_from_tuple<T>(tp) 对 J 从 0 到 N-1(其中 N 是 std::tuple_size<typename std::remove_reference<Tp>::type>::value)返回 T(std::get<J>(std::forward<Tp>(tp))…)。与 C++17 的 std::make_from_tuple 相同。函数名称与 C++17 的名称不匹配,以避免当两者都可见或在非限定调用时发生歧义。
tuple_for_each(tp, f)
template<class Tp, class F> constexpr F tuple_for_each(Tp&& tp, F&& f);
tuple_for_each(tp, f) 通过对 J 从 0 到 N-1(其中 N 是 std::tuple_size<typename std::remove_reference<Tp>::type>::value)求值表达式 f(std::get<J>(std::forward<Tp>(tp))),按顺序将函数对象 f 应用于 tp 的每个元素。
返回 std::forward<F>(f)。
tuple_transform(f, tp…)
template<class F, class... Tp> constexpr /*...*/ tuple_transform(F const& f, Tp&&... tp);
tuple_transform(f, tp…) 接受一个函数对象 f,后跟一个或多个长度相等的元组(std::tuple、std::pair 和 std::array 被视为元组)。
可调用对象 f 必须接受与元组数量相同数量的参数。函数对象将与每个元组的第一个元素、第二个元素,依此类推,一起被调用,如同对 J 从 0 到 N-1(其中 N 是元组的长度)求值表达式 f(std::get<J>(std::forward<Tp>(tp))…) 一样。
处理元组元素的顺序是未指定的。
结果作为 std::tuple<T…> 返回,其中 T… 从 f 的返回值推导而来(左值引用被保留,右值引用按值返回)。
便捷头文件, <boost/mp11.hpp>
便利头文件 <boost/mp11.hpp> 包含此参考中之前列出的所有头文件。
MPL 支持, <boost/mp11/mpl.hpp>
当包含头文件 <boost/mp11/mpl.hpp> 时,它会定义必要的支持基础设施,使 mp_list 和 std::tuple 成为有效的 MPL 序列。
|
注意
|
mpl.hpp 不被 <boost/mp11.hpp> 包含。 |
也可以仅通过包含 <boost/mp11/mpl_list.hpp> 来启用对 mp_list 的支持,通过包含 <boost/mp11/mpl_tuple.hpp> 来启用对 std::tuple 的支持。这可能是必需的,因为某些库(如 Boost.Fusion)为 std::tuple 包含了自己的 MPL 支持,这与 Mp11 的支持冲突。
using L = mpl::copy<Sequence, mpl::back_inserter<mp11::mp_list<>>>::type;
附录 A:版权、许可和致谢
本文档
-
版权 2017-2019 Peter Dimov
-
版权 2017 Bjørn Reese
“Simple C++11 metaprogramming” 系列文章已由 Glen Fernandes 荣幸地转换为 Asciidoc 格式,以便纳入此文档。