forked from boostorg/mp11
Merge branch 'develop'
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -7,11 +7,13 @@ See accompanying file LICENSE_1_0.txt or copy at
|
|||||||
http://www.boost.org/LICENSE_1_0.txt
|
http://www.boost.org/LICENSE_1_0.txt
|
||||||
////
|
////
|
||||||
|
|
||||||
# Boost.Mp11
|
# Boost.Mp11: A C++11 metaprogramming library
|
||||||
Peter Dimov
|
Peter Dimov
|
||||||
:toc: left
|
:toc: left
|
||||||
:toclevels: 3
|
:toclevels: 3
|
||||||
:idprefix:
|
:idprefix:
|
||||||
|
:listing-caption: Code Example
|
||||||
|
:table-caption: Illustration
|
||||||
|
|
||||||
:leveloffset: +1
|
:leveloffset: +1
|
||||||
|
|
||||||
|
@@ -19,36 +19,141 @@ http://www.boost.org/LICENSE_1_0.txt
|
|||||||
|
|
||||||
`mp_assign<L1<T1...>, L2<T2...>>` is an alias for `L1<T2...>`. That is, it replaces the elements of `L1` with those of `L2`.
|
`mp_assign<L1<T1...>, L2<T2...>>` is an alias for `L1<T2...>`. That is, it replaces the elements of `L1` with those of `L2`.
|
||||||
|
|
||||||
|
.Using mp_assign with mp_list and std::tuple
|
||||||
|
```
|
||||||
|
using L1 = std::tuple<long>;
|
||||||
|
using L2 = mp_list<int, float>;
|
||||||
|
|
||||||
|
using R1 = mp_assign<L1, L2>; // std::tuple<int, float>
|
||||||
|
```
|
||||||
|
|
||||||
|
.Using mp_assign with mp_list and std::pair
|
||||||
|
```
|
||||||
|
using L1 = std::pair<long, char>;
|
||||||
|
using L2 = mp_list<int, float>;
|
||||||
|
|
||||||
|
using R1 = mp_assign<L1, L2>; // std::pair<int, float>
|
||||||
|
```
|
||||||
|
|
||||||
## mp_clear<L>
|
## mp_clear<L>
|
||||||
|
|
||||||
template<class L> using mp_clear = mp_assign<L, mp_list<>>;
|
template<class L> using mp_clear = mp_assign<L, mp_list<>>;
|
||||||
|
|
||||||
`mp_clear<L<T...>>` is an alias for `L<>`, that is, it removes the elements of `L`.
|
`mp_clear<L<T...>>` is an alias for `L<>`, that is, it removes the elements of `L`.
|
||||||
|
|
||||||
|
.Using mp_clear with std::tuple
|
||||||
|
```
|
||||||
|
using L1 = std::tuple<int, float>;
|
||||||
|
using R1 = mp_clear<L1>; // std::tuple<>
|
||||||
|
```
|
||||||
|
|
||||||
## mp_transform<F, L...>
|
## mp_transform<F, L...>
|
||||||
|
|
||||||
template<template<class...> class F, class... L> using mp_transform = /*...*/;
|
template<template<class...> class F, class... L> using mp_transform = /*...*/;
|
||||||
|
|
||||||
`mp_transform<F, L1<T1...>, L2<T2...>, ..., Ln<Tn...>>` applies `F` to each successive tuple of elements and returns `L1<F<T1, T2, ..., Tn>...>`.
|
`mp_transform<F, L1<T1...>, L2<T2...>, ..., Ln<Tn...>>` applies `F` to each successive tuple of elements and returns `L1<F<T1, T2, ..., Tn>...>`.
|
||||||
|
|
||||||
|
.Using mp_transform to produce a list of pointers from a list of pointees
|
||||||
|
```
|
||||||
|
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 mp_transform to compare the contents of two lists of types
|
||||||
|
```
|
||||||
|
using L1 = std::tuple<void, int, float>;
|
||||||
|
using L2 = mp_list<void, int, float>;
|
||||||
|
|
||||||
|
using R1 = mp_all<mp_transform<std::is_same, L1, L2>>; // mp_true
|
||||||
|
```
|
||||||
|
|
||||||
|
.Using mp_transform to compare the contents of two lists of integral constants
|
||||||
|
```
|
||||||
|
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_all<mp_transform<eq, L1, L2>>; // mp_true
|
||||||
|
```
|
||||||
|
|
||||||
|
.mp_transform on one list
|
||||||
|
[cols="<.^4m,4*^.^1m",options="header",width=85%]
|
||||||
|
|===
|
||||||
|
^|List
|
||||||
|
4+|Contents
|
||||||
|
5+|
|
||||||
|
|*L1*|A0|A1|...|An
|
||||||
|
5+|
|
||||||
|
|*mp_transform<F, L1>*|F<A0>|F<A1>|...|F<An>
|
||||||
|
|===
|
||||||
|
|
||||||
|
.mp_transform on two lists
|
||||||
|
[cols="<.^4m,4*^.^1m",options="header",width=85%]
|
||||||
|
|===
|
||||||
|
^|List
|
||||||
|
4+|Contents
|
||||||
|
5+|
|
||||||
|
|*L1*|A0|A1|...|An
|
||||||
|
5+|
|
||||||
|
|*L2*|B0|B1|...|Bn
|
||||||
|
5+|
|
||||||
|
|*mp_transform<F, L1, L2>*|F<A0,B0>|F<A1,B1>|...|F<An,Bn>
|
||||||
|
|===
|
||||||
|
|
||||||
## mp_transform_q<Q, L...>
|
## mp_transform_q<Q, L...>
|
||||||
|
|
||||||
template<class Q, class... L> using mp_transform_q = mp_transform<Q::template fn, L...>;
|
template<class Q, class... L> using mp_transform_q =
|
||||||
|
mp_transform<Q::template fn, L...>;
|
||||||
|
|
||||||
As `mp_transform`, but takes a quoted metafunction.
|
As `mp_transform`, but takes a quoted metafunction.
|
||||||
|
|
||||||
|
.Using mp_transform_q to count the occurences of `void` in a list
|
||||||
|
```
|
||||||
|
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...>
|
## mp_transform_if<P, F, L...>
|
||||||
|
|
||||||
template<template<class...> class P, template<class...> class F, class L...> using mp_transform_if = /*...*/;
|
template<template<class...> class P, template<class...> class F, class L...>
|
||||||
|
using mp_transform_if = /*...*/;
|
||||||
|
|
||||||
`mp_transform_if<P, F, L1, L2, ..., Ln>` replaces the elements of the list `L1` for which `mp_to_bool<P<T1, T2, ..., Tn>>` is `mp_true` with
|
`mp_transform_if<P, F, L1, L2, ..., Ln>` replaces the elements of the list `L1` for which `mp_to_bool<P<T1, T2, ..., Tn>>` is `mp_true` with
|
||||||
`F<T1, T2, ..., Tn>`, and returns the result, where `Ti` are the corresponding elements of `Li`.
|
`F<T1, T2, ..., Tn>`, and returns the result, where `Ti` are the corresponding elements of `Li`.
|
||||||
|
|
||||||
|
.Using mp_transform_if to replace the occurences of 'void' in a list with the corresponding elements of a second list
|
||||||
|
```
|
||||||
|
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...>
|
## 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...>;
|
template<class Qp, class Qf, class... L> using mp_transform_if_q =
|
||||||
|
mp_transform_if<Qp::template fn, Qf::template fn, L...>;
|
||||||
|
|
||||||
As `mp_transform_if`, but takes a quoted metafunction.
|
As `mp_transform_if`, but takes quoted metafunctions.
|
||||||
|
|
||||||
|
.Using mp_transform_if_q to replace the occurences of 'void' in a list with the corresponding elements of a second list
|
||||||
|
```
|
||||||
|
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_fill<L, V>
|
## mp_fill<L, V>
|
||||||
|
|
||||||
@@ -56,6 +161,18 @@ As `mp_transform_if`, but takes a quoted metafunction.
|
|||||||
|
|
||||||
`mp_fill<L<T...>, V>` returns `L<V, V, ..., V>`, with the result having the same size as the input.
|
`mp_fill<L<T...>, V>` returns `L<V, V, ..., V>`, with the result having the same size as the input.
|
||||||
|
|
||||||
|
.Using mp_fill with std::tuple
|
||||||
|
```
|
||||||
|
using L1 = std::tuple<void, int, float>;
|
||||||
|
using R1 = mp_fill<L1, double>; // std::tuple<double, double, double>
|
||||||
|
```
|
||||||
|
|
||||||
|
.Using mp_fill with std::pair
|
||||||
|
```
|
||||||
|
using L1 = std::pair<int, float>;
|
||||||
|
using R1 = mp_fill<L1, void>; // std::pair<void, void>
|
||||||
|
```
|
||||||
|
|
||||||
## mp_count<L, V>
|
## mp_count<L, V>
|
||||||
|
|
||||||
template<class L, class V> using mp_count = /*...*/;
|
template<class L, class V> using mp_count = /*...*/;
|
||||||
@@ -94,6 +211,32 @@ Same as `mp_repeat_c` but with a type argument `N`. The number of copies is `N::
|
|||||||
the Cartesian product of the lists, as if the elements `Ui` are formed by `n` nested loops, each traversing `Li`.
|
the Cartesian product of the lists, as if the elements `Ui` are formed by `n` nested loops, each traversing `Li`.
|
||||||
It returns a list of type `L1` containing the results of the application of `F`.
|
It returns a list of type `L1` containing the results of the application of `F`.
|
||||||
|
|
||||||
|
.mp_product on two lists
|
||||||
|
[cols="<.^4m,4*^.^1m",options="header",width=85%]
|
||||||
|
|===
|
||||||
|
^|List
|
||||||
|
4+|Contents
|
||||||
|
5+|
|
||||||
|
|*L1*|A0|A1|...|An
|
||||||
|
5+|
|
||||||
|
|*L2*|B0|B1|...|Bm
|
||||||
|
5+|
|
||||||
|
|*mp_product<F, L1, L2>*
|
||||||
|
|F<A0,B0>
|
||||||
|
F<A0,B1>
|
||||||
|
...
|
||||||
|
F<A0,Bm>
|
||||||
|
|F<A1,B0>
|
||||||
|
F<A1,B1>
|
||||||
|
...
|
||||||
|
F<A1,Bm>
|
||||||
|
|...
|
||||||
|
|F<An,B0>
|
||||||
|
F<An,B1>
|
||||||
|
...
|
||||||
|
F<An,Bm>
|
||||||
|
|===
|
||||||
|
|
||||||
## mp_product_q<Q, L...>
|
## mp_product_q<Q, L...>
|
||||||
|
|
||||||
template<class Q, class... L> using mp_product_q = mp_product<Q::template fn, L...>;
|
template<class Q, class... L> using mp_product_q = mp_product<Q::template fn, L...>;
|
||||||
@@ -130,7 +273,7 @@ where `T` is the type of `N::value`.
|
|||||||
|
|
||||||
template<class L, std::size_t I> using mp_at_c = /*...*/;
|
template<class L, std::size_t I> using mp_at_c = /*...*/;
|
||||||
|
|
||||||
`mp_at_c<L, I>` returns the `I`th element of `L`, zero-based.
|
`mp_at_c<L, I>` returns the `I`-th element of `L`, zero-based.
|
||||||
|
|
||||||
## mp_at<L, I>
|
## mp_at<L, I>
|
||||||
|
|
||||||
@@ -152,25 +295,29 @@ Same as `mp_take_c`, but with a type argument `N`. `N::value` must be a nonnegat
|
|||||||
|
|
||||||
## mp_insert_c<L, I, T...>
|
## 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...>>;
|
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...>>;
|
||||||
|
|
||||||
Inserts the elements `T...` into the list `L` at position `I` (a zero-based index).
|
Inserts the elements `T...` into the list `L` at position `I` (a zero-based index).
|
||||||
|
|
||||||
## mp_insert<L, I, T...>
|
## 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...>>;
|
template<class L, class I, class... T> using mp_insert =
|
||||||
|
mp_append<mp_take<L, I>, mp_push_front<mp_drop<L, I>, T...>>;
|
||||||
|
|
||||||
Same as `mp_insert_c`, but with a type argument `I`.
|
Same as `mp_insert_c`, but with a type argument `I`.
|
||||||
|
|
||||||
## mp_erase_c<L, I, J>
|
## mp_erase_c<L, I, J>
|
||||||
|
|
||||||
template<class L, std::size_t I, std::size_t J> using mp_erase = mp_append<mp_take_c<L, I>, mp_drop_c<L, 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>>;
|
||||||
|
|
||||||
Removes from the list `L` the elements with indices from `I` (inclusive) to `J` (exclusive).
|
Removes from the list `L` the elements with indices from `I` (inclusive) to `J` (exclusive).
|
||||||
|
|
||||||
## mp_erase<L, I, J>
|
## 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>>;
|
template<class L, class I, class J> using mp_erase =
|
||||||
|
mp_append<mp_take<L, I>, mp_drop<L, J>>;
|
||||||
|
|
||||||
Same as `mp_erase_c`, but with a type arguments `I` and `J`.
|
Same as `mp_erase_c`, but with a type arguments `I` and `J`.
|
||||||
|
|
||||||
@@ -229,6 +376,14 @@ for the elements of `L<U1...>` and `mp_false` for the elements of `L<U2...>`. Re
|
|||||||
|
|
||||||
`mp_sort<L, P>` sorts the list `L` according to the strict weak ordering `mp_to_bool<P<T, U>>`.
|
`mp_sort<L, P>` sorts the list `L` according to the strict weak ordering `mp_to_bool<P<T, U>>`.
|
||||||
|
|
||||||
|
.Using mp_sort to sort a list of std::ratio values
|
||||||
|
----
|
||||||
|
#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_find<L, V>
|
## mp_find<L, V>
|
||||||
|
|
||||||
template<class L, class V> using mp_find = /*...*/;
|
template<class L, class V> using mp_find = /*...*/;
|
||||||
@@ -258,7 +413,8 @@ is `mp_size<L>`.
|
|||||||
|
|
||||||
## mp_reverse_fold<L, V, F>
|
## mp_reverse_fold<L, V, F>
|
||||||
|
|
||||||
template<class L, class V, template<class...> class F> using mp_reverse_fold = /*...*/;
|
template<class L, class V, template<class...> class F> using mp_reverse_fold =
|
||||||
|
/*...*/;
|
||||||
|
|
||||||
`mp_reverse_fold<L<T1, T2, ..., Tn>, V, F>` is `F<T1, F<T2, F<..., F<Tn, V>>>>`, or `V`, if `L` is empty.
|
`mp_reverse_fold<L<T1, T2, ..., Tn>, V, F>` is `F<T1, F<T2, F<..., F<Tn, V>>>>`, or `V`, if `L` is empty.
|
||||||
|
|
||||||
@@ -270,19 +426,22 @@ is `mp_size<L>`.
|
|||||||
|
|
||||||
## mp_all_of<L, P>
|
## 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 >;
|
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>` is `mp_true` when `P` holds for all elements of `L`, `mp_false` otherwise. When `L` is empty, the result is `mp_true`.
|
`mp_all_of<L, P>` is `mp_true` when `P` holds for all elements of `L`, `mp_false` otherwise. When `L` is empty, the result is `mp_true`.
|
||||||
|
|
||||||
## mp_none_of<L, P>
|
## 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 >;
|
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>` is `mp_true` when `P` holds for no element of `L`, `mp_false` otherwise. When `L` is empty, the result is `mp_true`.
|
`mp_none_of<L, P>` is `mp_true` when `P` holds for no element of `L`, `mp_false` otherwise. When `L` is empty, the result is `mp_true`.
|
||||||
|
|
||||||
## mp_any_of<L, P>
|
## 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 >;
|
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>` is `mp_true` when `P` holds for at least one element of `L`, `mp_false` otherwise. When `L` is empty, the result is `mp_false`.
|
`mp_any_of<L, P>` is `mp_true` when `P` holds for at least one element of `L`, `mp_false` otherwise. When `L` is empty, the result is `mp_false`.
|
||||||
|
|
||||||
@@ -294,12 +453,47 @@ is `mp_size<L>`.
|
|||||||
|
|
||||||
Returns `std::forward<F>(f)`.
|
Returns `std::forward<F>(f)`.
|
||||||
|
|
||||||
|
.Using mp_for_each and a C++14 lambda to print a tuple
|
||||||
|
```
|
||||||
|
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;
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## mp_with_index<N>(i, f)
|
## mp_with_index<N>(i, f)
|
||||||
|
|
||||||
template<std::size_t N, class F> decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) mp_with_index( std::size_t i, F && 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)` calls `f` with `mp_size_t<i>()` and returns the result. `i` must be less than `N`.
|
`mp_with_index<N>(i, f)` calls `f` with `mp_size_t<i>()` and returns the result. `i` must be less than `N`.
|
||||||
|
Only `constexpr` on C++14 and higher.
|
||||||
|
|
||||||
template<class N, class F> decltype(std::declval<F>()(std::declval<mp_size_t<0>>())) mp_with_index( std::size_t i, F && f );
|
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>>()));
|
||||||
|
|
||||||
Returns `mp_with_index<N::value>(i, f)`.
|
Returns `mp_with_index<N::value>(i, f)`.
|
||||||
|
|
||||||
|
.Using mp_with_index and a C++14 lambda to print the active element of a variant
|
||||||
|
```
|
||||||
|
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;
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
@@ -57,7 +57,8 @@ As `mp_bind`, but takes a quoted metafunction.
|
|||||||
|
|
||||||
## mp_bind_front_q<Q, T...>
|
## mp_bind_front_q<Q, T...>
|
||||||
|
|
||||||
template<class Q, class... T> using mp_bind_front_q = mp_bind_front<Q::template fn, T...>;
|
template<class Q, class... T> using mp_bind_front_q =
|
||||||
|
mp_bind_front<Q::template fn, T...>;
|
||||||
|
|
||||||
As `mp_bind_front`, but takes a quoted metafunction.
|
As `mp_bind_front`, but takes a quoted metafunction.
|
||||||
|
|
||||||
@@ -69,6 +70,7 @@ As `mp_bind_front`, but takes a quoted metafunction.
|
|||||||
|
|
||||||
## mp_bind_back_q<Q, T...>
|
## mp_bind_back_q<Q, T...>
|
||||||
|
|
||||||
template<class Q, class... T> using mp_bind_back_q = mp_bind_back<Q::template fn, T...>;
|
template<class Q, class... T> using mp_bind_back_q =
|
||||||
|
mp_bind_back<Q::template fn, T...>;
|
||||||
|
|
||||||
As `mp_bind_back`, but takes a quoted metafunction.
|
As `mp_bind_back`, but takes a quoted metafunction.
|
||||||
|
@@ -16,15 +16,24 @@ for example `mp_list<char[], void>`, `mp_list<>`, `std::tuple<int, float, char>`
|
|||||||
A _metafunction_ is a class template or a template alias whose parameters are all types, for example `std::add_pointer_t`,
|
A _metafunction_ is a class template or a template alias whose parameters are all types, for example `std::add_pointer_t`,
|
||||||
`std::is_const`, `mp_second`, `mp_push_front`, `mp_list`, `std::tuple`, `std::pair`, `std::shared_ptr`, or
|
`std::is_const`, `mp_second`, `mp_push_front`, `mp_list`, `std::tuple`, `std::pair`, `std::shared_ptr`, or
|
||||||
|
|
||||||
template<class...> using F1 = void;
|
```
|
||||||
template<class T> using F2 = T*;
|
template<class...> using F1 = void;
|
||||||
template<class... T> using F3 = std::integral_constant<std::size_t, sizeof...(T)>;
|
|
||||||
|
template<class T> using F2 = T*;
|
||||||
|
|
||||||
|
template<class... T> using F3 = std::integral_constant<std::size_t, sizeof...(T)>;
|
||||||
|
```
|
||||||
|
|
||||||
A _quoted metafunction_ is a class with a public metafunction member called `fn`, for example
|
A _quoted metafunction_ is a class with a public metafunction member called `fn`, for example
|
||||||
|
|
||||||
struct Q1 { template<class...> using fn = void; };
|
```
|
||||||
struct Q2 { template<class T> using fn = T*; };
|
struct Q1 { template<class...> using fn = void; };
|
||||||
struct Q3 { template<class... T> using fn = std::integral_constant<std::size_t, sizeof...(T)>; };
|
|
||||||
|
struct Q2 { template<class T> using fn = T*; };
|
||||||
|
|
||||||
|
struct Q3 { template<class... T> using fn =
|
||||||
|
std::integral_constant<std::size_t, sizeof...(T)>; };
|
||||||
|
```
|
||||||
|
|
||||||
An _integral constant type_ is a class with a public member `value` that is an integral constant in the C++ sense. For example,
|
An _integral constant type_ is a class with a public member `value` that is an integral constant in the C++ sense. For example,
|
||||||
`std::integral_constant<int, 7>`, or
|
`std::integral_constant<int, 7>`, or
|
||||||
@@ -35,5 +44,10 @@ A _set_ is a list whose elements are unique.
|
|||||||
|
|
||||||
A _map_ is a list of lists, the inner lists having at least one element (the key.) The keys of the map must be unique. For example,
|
A _map_ is a list of lists, the inner lists having at least one element (the key.) The keys of the map must be unique. For example,
|
||||||
|
|
||||||
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]>>;
|
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]>>;
|
||||||
|
```
|
||||||
|
@@ -118,7 +118,7 @@ int main()
|
|||||||
tuple_for_each( mp_product<mp_list, L, L>(), test_result() );
|
tuple_for_each( mp_product<mp_list, L, L>(), test_result() );
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
## Writing `common_type` specializations
|
## Writing common_type Specializations
|
||||||
|
|
||||||
The standard trait `std::common_type`, used to obtain a type to which all of its arguments can convert without
|
The standard trait `std::common_type`, used to obtain a type to which all of its arguments can convert without
|
||||||
unnecessary loss of precision, can be user-specialized when its default implementation (based on the ternary `?:`
|
unnecessary loss of precision, can be user-specialized when its default implementation (based on the ternary `?:`
|
||||||
@@ -163,7 +163,8 @@ combined into their common type, and we take the union of the set of error types
|
|||||||
Therefore,
|
Therefore,
|
||||||
```
|
```
|
||||||
template<class T1, class E1, class T2, class E2> using common_expected =
|
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>;
|
mp_rename<mp_push_front<mp_unique<mp_append<E1, E2>>, common_type_t<T1, T2>>,
|
||||||
|
expected>;
|
||||||
|
|
||||||
namespace std
|
namespace std
|
||||||
{
|
{
|
||||||
@@ -181,10 +182,11 @@ the `E` types. This makes our job easier. `mp_unique<mp_append<E1, E2>>` gives u
|
|||||||
removed; we then add `common_type_t<T1, T2>` to the front via `mp_push_front`; and finally, we `mp_rename` the resultant `mp_list`
|
removed; we then add `common_type_t<T1, T2>` to the front via `mp_push_front`; and finally, we `mp_rename` the resultant `mp_list`
|
||||||
to `expected`.
|
to `expected`.
|
||||||
|
|
||||||
## Fixing `tuple_cat`
|
## Fixing tuple_cat
|
||||||
|
|
||||||
The article http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html#[Simple C++11 metaprogramming] builds an
|
The article http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html#[Simple C++11 metaprogramming] builds an
|
||||||
implementation of the standard function `tuple_cat`, with the end result given below:
|
implementation of the standard function `tuple_cat`, with the end result given below:
|
||||||
|
|
||||||
```
|
```
|
||||||
template<class L> using F = mp_iota<mp_size<L>>;
|
template<class L> using F = mp_iota<mp_size<L>>;
|
||||||
|
|
||||||
@@ -202,7 +204,9 @@ template<class... Tp,
|
|||||||
|
|
||||||
// inner
|
// inner
|
||||||
|
|
||||||
using list1 = mp_list<mp_rename<typename std::remove_reference<Tp>::type, mp_list>...>;
|
using list1 = mp_list<
|
||||||
|
mp_rename<typename std::remove_reference<Tp>::type, mp_list>...>;
|
||||||
|
|
||||||
using list2 = mp_iota_c<N>;
|
using list2 = mp_iota_c<N>;
|
||||||
|
|
||||||
using list3 = mp_transform<mp_fill, list1, list2>;
|
using list3 = mp_transform<mp_fill, list1, list2>;
|
||||||
@@ -217,11 +221,14 @@ template<class... Tp,
|
|||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
return tuple_cat_<R>( inner(), outer(), std::forward_as_tuple( std::forward<Tp>(tp)... ) );
|
return tuple_cat_<R>( inner(), outer(),
|
||||||
|
std::forward_as_tuple( std::forward<Tp>(tp)... ) );
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
This function, however, is not entirely correct, in that it doesn't handle some cases properly. For example,
|
This function, however, is not entirely correct, in that it doesn't handle some cases properly. For example,
|
||||||
trying to concatenate tuples containing move-only elements such as `unique_ptr` fails:
|
trying to concatenate tuples containing move-only elements such as `unique_ptr` fails:
|
||||||
|
|
||||||
```
|
```
|
||||||
std::tuple<std::unique_ptr<int>> t1;
|
std::tuple<std::unique_ptr<int>> t1;
|
||||||
std::tuple<std::unique_ptr<float>> t2;
|
std::tuple<std::unique_ptr<float>> t2;
|
||||||
@@ -247,7 +254,7 @@ auto result = ::tuple_cat( t1, t2 );
|
|||||||
Let's fix these one by one. Support for move-only types is easy, if one knows where to look. The problem is
|
Let's fix these one by one. Support for move-only types is easy, if one knows where to look. The problem is
|
||||||
that `Tp` that we're passing to the helper `tuple_cat_` is (correctly) `tuple<unique_ptr<int>&&, unique_ptr<float>&&>`,
|
that `Tp` that we're passing to the helper `tuple_cat_` is (correctly) `tuple<unique_ptr<int>&&, unique_ptr<float>&&>`,
|
||||||
but `std::get<0>(tp)` still returns `unique_ptr<int>&`, because `tp` is an lvalue. This behavior is a bit
|
but `std::get<0>(tp)` still returns `unique_ptr<int>&`, because `tp` is an lvalue. This behavior is a bit
|
||||||
surprising, but consistent with how rvalue reference members are treated by the language.
|
surprising, but is intended to prevent inadvertent double moves.
|
||||||
|
|
||||||
Long story short, we need `std::move(tp)` in `tuple_cat_` to make `tp` an rvalue:
|
Long story short, we need `std::move(tp)` in `tuple_cat_` to make `tp` an rvalue:
|
||||||
|
|
||||||
@@ -266,6 +273,7 @@ primitive that is inexplicably missing from the standard library:
|
|||||||
typename std::remove_reference<T>::type>::type;
|
typename std::remove_reference<T>::type>::type;
|
||||||
|
|
||||||
and then by using `remove_cv_ref<Tp>` in place of `typename std::remove_reference<Tp>::type`:
|
and then by using `remove_cv_ref<Tp>` in place of `typename std::remove_reference<Tp>::type`:
|
||||||
|
|
||||||
```
|
```
|
||||||
template<class... Tp,
|
template<class... Tp,
|
||||||
class R = mp_append<std::tuple<>, remove_cv_ref<Tp>...>>
|
class R = mp_append<std::tuple<>, remove_cv_ref<Tp>...>>
|
||||||
@@ -279,6 +287,7 @@ template<class... Tp,
|
|||||||
|
|
||||||
// ...
|
// ...
|
||||||
```
|
```
|
||||||
|
|
||||||
Finally, tuple-like types. We've so far exploited the fact that `std::pair` and `std::tuple` are valid Mp11 lists,
|
Finally, tuple-like types. We've so far exploited the fact that `std::pair` and `std::tuple` are valid Mp11 lists,
|
||||||
but in general, arbitrary tuple-like types aren't, so we need to convert them into such. For that, we'll need to
|
but in general, arbitrary tuple-like types aren't, so we need to convert them into such. For that, we'll need to
|
||||||
define a metafunction `from_tuple_like` that will take an arbitrary tuple-like type and will return, in our case,
|
define a metafunction `from_tuple_like` that will take an arbitrary tuple-like type and will return, in our case,
|
||||||
@@ -289,6 +298,7 @@ convenient.
|
|||||||
|
|
||||||
What we need is, given a tuple-like type `Tp`, to obtain `mp_list<std::tuple_element<0, Tp>::type, std::tuple_element<1, Tp>::type,
|
What we need is, given a tuple-like type `Tp`, to obtain `mp_list<std::tuple_element<0, Tp>::type, std::tuple_element<1, Tp>::type,
|
||||||
..., std::tuple_element<N-1, Tp>::type>`, where `N` is `tuple_size<Tp>::value`. Here's one way to do it:
|
..., std::tuple_element<N-1, Tp>::type>`, where `N` is `tuple_size<Tp>::value`. Here's one way to do it:
|
||||||
|
|
||||||
```
|
```
|
||||||
template<class T, class I> using tuple_element =
|
template<class T, class I> using tuple_element =
|
||||||
typename std::tuple_element<I::value, T>::type;
|
typename std::tuple_element<I::value, T>::type;
|
||||||
@@ -296,6 +306,7 @@ template<class T, class I> using tuple_element =
|
|||||||
template<class T> using from_tuple_like =
|
template<class T> using from_tuple_like =
|
||||||
mp_product<tuple_element, mp_list<T>, mp_iota<std::tuple_size<T>>>;
|
mp_product<tuple_element, mp_list<T>, mp_iota<std::tuple_size<T>>>;
|
||||||
```
|
```
|
||||||
|
|
||||||
(`mp_iota<N>` is an algorithm that returns an `mp_list` with elements `mp_size_t<0>`, `mp_size_t<1>`, ..., `mp_size_t<N-1>`.)
|
(`mp_iota<N>` is an algorithm that returns an `mp_list` with elements `mp_size_t<0>`, `mp_size_t<1>`, ..., `mp_size_t<N-1>`.)
|
||||||
|
|
||||||
Remember that `mp_product<F, L1, L2>` performs the equivalent of two nested loops over the elements of `L1` and `L2`,
|
Remember that `mp_product<F, L1, L2>` performs the equivalent of two nested loops over the elements of `L1` and `L2`,
|
||||||
@@ -310,6 +321,7 @@ For completeness's sake, here's another, more traditional way to achieve the sam
|
|||||||
mp_transform_q<mp_bind_front<tuple_element, T>, mp_iota<std::tuple_size<T>>>;
|
mp_transform_q<mp_bind_front<tuple_element, T>, mp_iota<std::tuple_size<T>>>;
|
||||||
|
|
||||||
With all these fixes applied, our fully operational `tuple_cat` now looks like this:
|
With all these fixes applied, our fully operational `tuple_cat` now looks like this:
|
||||||
|
|
||||||
```
|
```
|
||||||
template<class L> using F = mp_iota<mp_size<L>>;
|
template<class L> using F = mp_iota<mp_size<L>>;
|
||||||
|
|
||||||
@@ -351,9 +363,11 @@ template<class... Tp,
|
|||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
return tuple_cat_<R>( inner(), outer(), std::forward_as_tuple( std::forward<Tp>(tp)... ) );
|
return tuple_cat_<R>( inner(), outer(),
|
||||||
|
std::forward_as_tuple( std::forward<Tp>(tp)... ) );
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Computing Return Types
|
## Computing Return Types
|
||||||
|
|
||||||
C++17 has a standard variant type, called `std::variant`. It also defines a function template
|
C++17 has a standard variant type, called `std::variant`. It also defines a function template
|
||||||
@@ -372,6 +386,7 @@ what `v1` and `v2` hold.
|
|||||||
|
|
||||||
A type that can hold either `int` or `float` already exists, called, surprisingly enough, `std::variant<int, float>`.
|
A type that can hold either `int` or `float` already exists, called, surprisingly enough, `std::variant<int, float>`.
|
||||||
Let's write our own function template `rvisit` that is the same as `visit` but returns a `variant`:
|
Let's write our own function template `rvisit` that is the same as `visit` but returns a `variant`:
|
||||||
|
|
||||||
```
|
```
|
||||||
template<class F, class... V> auto rvisit( F&& f, V&&... v )
|
template<class F, class... V> auto rvisit( F&& f, V&&... v )
|
||||||
{
|
{
|
||||||
@@ -382,6 +397,7 @@ template<class F, class... V> auto rvisit( F&& f, V&&... v )
|
|||||||
std::forward<V>( v )... );
|
std::forward<V>( v )... );
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
What this does is basically calls `std::visit` to do the work, but instead of passing it `f`, we pass a lambda that does the same as `f` except
|
What this does is basically calls `std::visit` to do the work, but instead of passing it `f`, we pass a lambda that does the same as `f` except
|
||||||
it converts the result to a common type `R`. `R` is supposed to be `std::variant<...>` where the ellipsis denotes the return types of
|
it converts the result to a common type `R`. `R` is supposed to be `std::variant<...>` where the ellipsis denotes the return types of
|
||||||
calling `f` with all possible combinations of variant values.
|
calling `f` with all possible combinations of variant values.
|
||||||
@@ -390,7 +406,8 @@ We'll first define a helper quoted metafunction `Qret<F>` that returns the resul
|
|||||||
|
|
||||||
template<class F> struct Qret
|
template<class F> struct Qret
|
||||||
{
|
{
|
||||||
template<class... T> using fn = decltype( std::declval<F>()( std::declval<T>()... ) );
|
template<class... T> using fn =
|
||||||
|
decltype( std::declval<F>()( std::declval<T>()... ) );
|
||||||
};
|
};
|
||||||
|
|
||||||
(Unfortunately, we can't just define this metafunction inside `rvisit`; the language prohibits defining template aliases inside functions.)
|
(Unfortunately, we can't just define this metafunction inside `rvisit`; the language prohibits defining template aliases inside functions.)
|
||||||
@@ -405,11 +422,12 @@ the same as `mp_product`, but for quoted metafunctions such as our `Qret<F>`.)
|
|||||||
|
|
||||||
One more step remains. Suppose that, as above, we're passing two variants of type `std::variant<short, int, float>` and `F` is
|
One more step remains. Suppose that, as above, we're passing two variants of type `std::variant<short, int, float>` and `F` is
|
||||||
`[]( auto const& x, auto const& y ){ return x + y; }`. This will generate `R` of length 9, one per each combination, but many of those
|
`[]( auto const& x, auto const& y ){ return x + y; }`. This will generate `R` of length 9, one per each combination, but many of those
|
||||||
elements will be the same, either `int` or `float`, and we need to filter out the duplicates. So,
|
elements will be the same, either `int` or `float`, and we need to filter out the duplicates. So, we pass the result to `mp_unique`:
|
||||||
|
|
||||||
using R = mp_unique<mp_product_q<Qret<F>, std::remove_reference_t<V>...>>;
|
using R = mp_unique<mp_product_q<Qret<F>, std::remove_reference_t<V>...>>;
|
||||||
|
|
||||||
and we're done:
|
and we're done:
|
||||||
|
|
||||||
```
|
```
|
||||||
#include <boost/mp11.hpp>
|
#include <boost/mp11.hpp>
|
||||||
#include <boost/core/demangle.hpp>
|
#include <boost/core/demangle.hpp>
|
||||||
@@ -422,7 +440,8 @@ using namespace boost::mp11;
|
|||||||
|
|
||||||
template<class F> struct Qret
|
template<class F> struct Qret
|
||||||
{
|
{
|
||||||
template<class... T> using fn = decltype( std::declval<F>()( std::declval<T>()... ) );
|
template<class... T> using fn =
|
||||||
|
decltype( std::declval<F>()( std::declval<T>()... ) );
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class F, class... V> auto rvisit( F&& f, V&&... v )
|
template<class F, class... V> auto rvisit( F&& f, V&&... v )
|
||||||
@@ -439,25 +458,26 @@ template<class T> std::string name()
|
|||||||
return boost::core::demangle( typeid(T).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()
|
int main()
|
||||||
{
|
{
|
||||||
std::variant<signed char, unsigned char, signed short, unsigned short,
|
std::variant<char, int, float> v1( 1 );
|
||||||
int, unsigned> v1( 1 );
|
|
||||||
|
|
||||||
std::cout << "(" << name<decltype(v1)>() << ")v1: ";
|
print_variant( "v1", v1 );
|
||||||
std::visit( []( auto const& x )
|
|
||||||
{ std::cout << "(" << name<decltype(x)>() << ")" << x << std::endl; }, v1 );
|
|
||||||
|
|
||||||
std::variant<int, float, double> v2( 2.0f );
|
std::variant<short, int, double> v2( 3.14 );
|
||||||
|
|
||||||
std::cout << "(" << name<decltype(v2)>() << ")v2: ";
|
print_variant( "v2", v2 );
|
||||||
std::visit( []( auto const& x )
|
|
||||||
{ std::cout << "(" << name<decltype(x)>() << ")" << x << std::endl; }, v2 );
|
|
||||||
|
|
||||||
auto v3 = rvisit( []( auto const& x, auto const& y ){ return x + y; }, v1, v2 );
|
auto v3 = rvisit( []( auto const& x, auto const& y ){ return x + y; }, v1, v2 );
|
||||||
|
|
||||||
std::cout << "(" << name<decltype(v3)>() << ")v3: ";
|
print_variant( "v3", v3 );
|
||||||
std::visit( []( auto const& x )
|
|
||||||
{ std::cout << "(" << name<decltype(x)>() << ")" << x << std::endl; }, v3 );
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@@ -27,10 +27,16 @@ Same as `std::void_t` from C++17.
|
|||||||
returns `mp_false`. If the application causes a substitution failure, returns `mp_false`. If all results are `mp_true`,
|
returns `mp_false`. If the application causes a substitution failure, returns `mp_false`. If all results are `mp_true`,
|
||||||
returns `mp_true`. `mp_and<>` is `mp_true`.
|
returns `mp_true`. `mp_and<>` is `mp_true`.
|
||||||
|
|
||||||
using R1 = mp_and<mp_true, mp_true>; // mp_true
|
.mp_and behavior
|
||||||
using R2 = mp_and<mp_false, void>; // mp_false, void is not reached
|
```
|
||||||
using R3 = mp_and<mp_false, mp_false>; // mp_false
|
using R1 = mp_and<mp_true, mp_true>; // mp_true
|
||||||
using R4 = mp_and<void, mp_true>; // mp_false (!)
|
|
||||||
|
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...>
|
## mp_all<T...>
|
||||||
|
|
||||||
@@ -41,10 +47,16 @@ returns `mp_true`. `mp_and<>` is `mp_true`.
|
|||||||
is an error because `void` does not have a nested `value`. The upside is that `mp_all` is potentially faster and does not
|
is an error because `void` does not have a nested `value`. The upside is that `mp_all` is potentially faster and does not
|
||||||
mask substitution failures as `mp_and` does.
|
mask substitution failures as `mp_and` does.
|
||||||
|
|
||||||
using R1 = mp_and<mp_true, mp_true>; // mp_true
|
.mp_all behavior
|
||||||
using R2 = mp_and<mp_false, void>; // compile-time error
|
```
|
||||||
using R3 = mp_and<mp_false, mp_false>; // mp_false
|
using R1 = mp_all<mp_true, mp_true>; // mp_true
|
||||||
using R4 = mp_and<void, mp_true>; // compile-time error
|
|
||||||
|
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...>
|
## mp_or<T...>
|
||||||
|
|
||||||
@@ -53,10 +65,16 @@ mask substitution failures as `mp_and` does.
|
|||||||
`mp_or<T...>` applies `mp_to_bool` to the types in `T...`, in order. If the result of an application is `mp_true`, `mp_or`
|
`mp_or<T...>` applies `mp_to_bool` to the types in `T...`, in order. If the result of an application is `mp_true`, `mp_or`
|
||||||
returns `mp_true`. If all results are `mp_false`, returns `mp_false`. `mp_or<>` is `mp_false`.
|
returns `mp_true`. If all results are `mp_false`, returns `mp_false`. `mp_or<>` is `mp_false`.
|
||||||
|
|
||||||
using R1 = mp_or<mp_true, mp_false>; // mp_true
|
.mp_or behavior
|
||||||
using R2 = mp_or<mp_true, void>; // mp_true, void is not reached
|
```
|
||||||
using R3 = mp_or<mp_false, mp_false>; // mp_false
|
using R1 = mp_or<mp_true, mp_false>; // mp_true
|
||||||
using R4 = mp_or<void, mp_true>; // compile-time error
|
|
||||||
|
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...>
|
## mp_any<T...>
|
||||||
|
|
||||||
@@ -65,10 +83,16 @@ returns `mp_true`. If all results are `mp_false`, returns `mp_false`. `mp_or<>`
|
|||||||
`mp_any<T...>` is `mp_true` if `mp_to_bool<U>` is `mp_true` for any type `U` in `T...`, `mp_false` otherwise. Same as
|
`mp_any<T...>` is `mp_true` if `mp_to_bool<U>` is `mp_true` for any type `U` in `T...`, `mp_false` otherwise. Same as
|
||||||
`mp_or`, but does not perform short-circuit evaluation.
|
`mp_or`, but does not perform short-circuit evaluation.
|
||||||
|
|
||||||
using R1 = mp_any<mp_true, mp_false>; // mp_true
|
.mp_any behavior
|
||||||
using R2 = mp_any<mp_true, void>; // compile-time error
|
```
|
||||||
using R3 = mp_any<mp_false, mp_false>; // mp_false
|
using R1 = mp_any<mp_true, mp_false>; // mp_true
|
||||||
using R4 = mp_any<void, mp_true>; // compile-time error
|
|
||||||
|
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...>
|
## mp_same<T...>
|
||||||
|
|
||||||
|
@@ -35,12 +35,14 @@ http://www.boost.org/LICENSE_1_0.txt
|
|||||||
|
|
||||||
## make_index_sequence<N>
|
## make_index_sequence<N>
|
||||||
|
|
||||||
template<std::size_t N> using make_index_sequence = make_integer_sequence<std::size_t, N>;
|
template<std::size_t N> using make_index_sequence =
|
||||||
|
make_integer_sequence<std::size_t, N>;
|
||||||
|
|
||||||
`make_index_sequence<N>` is `index_sequence<0, 1, ..., N-1>`. Same as C++14's `std::make_index_sequence`.
|
`make_index_sequence<N>` is `index_sequence<0, 1, ..., N-1>`. Same as C++14's `std::make_index_sequence`.
|
||||||
|
|
||||||
## index_sequence_for<T...>
|
## index_sequence_for<T...>
|
||||||
|
|
||||||
template<class... T> using index_sequence_for = make_integer_sequence<std::size_t, sizeof...(T)>;
|
template<class... T> using index_sequence_for =
|
||||||
|
make_integer_sequence<std::size_t, sizeof...(T)>;
|
||||||
|
|
||||||
`index_sequence_for<N>` is `make_index_sequence<sizeof...(T)>`. Same as C++14's `std::index_sequence_for`.
|
`index_sequence_for<N>` is `make_index_sequence<sizeof...(T)>`. Same as C++14's `std::index_sequence_for`.
|
||||||
|
@@ -19,14 +19,20 @@ For an Mp11 integral constant type `T`, `T::value` is an integral constant in th
|
|||||||
|
|
||||||
template<bool B> using mp_bool = std::integral_constant<bool, B>;
|
template<bool B> using mp_bool = std::integral_constant<bool, B>;
|
||||||
|
|
||||||
|
Same as `std::bool_constant` in C++17.
|
||||||
|
|
||||||
## mp_true
|
## mp_true
|
||||||
|
|
||||||
using mp_true = mp_bool<true>;
|
using mp_true = mp_bool<true>;
|
||||||
|
|
||||||
|
Same as `std::true_type`.
|
||||||
|
|
||||||
## mp_false
|
## mp_false
|
||||||
|
|
||||||
using mp_false = mp_bool<false>;
|
using mp_false = mp_bool<false>;
|
||||||
|
|
||||||
|
Same as `std::false_type`.
|
||||||
|
|
||||||
## mp_to_bool<T>
|
## mp_to_bool<T>
|
||||||
|
|
||||||
template<class T> using mp_to_bool = mp_bool<static_cast<bool>(T::value)>;
|
template<class T> using mp_to_bool = mp_bool<static_cast<bool>(T::value)>;
|
||||||
|
@@ -28,14 +28,23 @@ the list.
|
|||||||
`mp_size<L>` returns the number of elements in the list `L`, as a `mp_size_t`. In other words, `mp_size<L<T...>>` is an alias for
|
`mp_size<L>` returns the number of elements in the list `L`, as a `mp_size_t`. In other words, `mp_size<L<T...>>` is an alias for
|
||||||
`mp_size_t<sizeof...(T)>`.
|
`mp_size_t<sizeof...(T)>`.
|
||||||
|
|
||||||
using L1 = mp_list<>;
|
.Using mp_size with mp_list
|
||||||
using R1 = mp_size<L1>; // mp_size_t\<0>
|
```
|
||||||
|
using L1 = mp_list<>;
|
||||||
|
using R1 = mp_size<L1>; // mp_size_t\<0>
|
||||||
|
```
|
||||||
|
|
||||||
using L2 = std::pair<int, int>;
|
.Using mp_size with std::pair
|
||||||
using R2 = mp_size<L2>; // mp_size_t\<2>
|
```
|
||||||
|
using L2 = std::pair<int, int>;
|
||||||
|
using R2 = mp_size<L2>; // mp_size_t\<2>
|
||||||
|
```
|
||||||
|
|
||||||
using L3 = std::tuple<float>;
|
.Using mp_size with std::tuple
|
||||||
using R3 = mp_size<L3>; // mp_size_t\<1>
|
```
|
||||||
|
using L3 = std::tuple<float>;
|
||||||
|
using R3 = mp_size<L3>; // mp_size_t\<1>
|
||||||
|
```
|
||||||
|
|
||||||
## mp_empty<L>
|
## mp_empty<L>
|
||||||
|
|
||||||
@@ -43,20 +52,38 @@ the list.
|
|||||||
|
|
||||||
`mp_empty<L>` is an alias for `mp_true` if the list `L` is empty, for `mp_false` otherwise.
|
`mp_empty<L>` is an alias for `mp_true` if the list `L` is empty, for `mp_false` otherwise.
|
||||||
|
|
||||||
|
.Using mp_empty with std::tuple
|
||||||
|
```
|
||||||
|
using L1 = std::tuple<float>;
|
||||||
|
using R1 = mp_empty<L1>; // mp_false
|
||||||
|
|
||||||
|
using L2 = std::tuple<>;
|
||||||
|
using R2 = mp_empty<L2>; // mp_true
|
||||||
|
```
|
||||||
|
|
||||||
## mp_front<L>
|
## mp_front<L>
|
||||||
|
|
||||||
template<class L> using mp_front = /*...*/;
|
template<class L> using mp_front = /*...*/;
|
||||||
|
|
||||||
`mp_front<L>` is the first element of the list `L`. That is, `mp_front<L<T1, T...>>` is an alias for `T1`.
|
`mp_front<L>` is the first element of the list `L`. That is, `mp_front<L<T1, T...>>` is an alias for `T1`.
|
||||||
|
|
||||||
using L1 = std::pair<int, float>;
|
.Using mp_front with std::pair
|
||||||
using R1 = mp_front<L1>; // int
|
```
|
||||||
|
using L1 = std::pair<int, float>;
|
||||||
|
using R1 = mp_front<L1>; // int
|
||||||
|
```
|
||||||
|
|
||||||
using L2 = std::tuple<float, double, long double>;
|
.Using mp_front with std::tuple
|
||||||
using R2 = mp_front<L2>; // float
|
```
|
||||||
|
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 mp_front with mp_list
|
||||||
using R3 = mp_front<L3>; // char[1]
|
```
|
||||||
|
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
|
||||||
|
using R3 = mp_front<L3>; // char[1]
|
||||||
|
```
|
||||||
|
|
||||||
## mp_pop_front<L>
|
## mp_pop_front<L>
|
||||||
|
|
||||||
@@ -64,11 +91,17 @@ the list.
|
|||||||
|
|
||||||
`mp_pop_front<L>` removes the first element of the list `L`. That is, `mp_pop_front<L<T1, T...>>` is an alias for `L<T...>`.
|
`mp_pop_front<L>` removes the first element of the list `L`. That is, `mp_pop_front<L<T1, T...>>` is an alias for `L<T...>`.
|
||||||
|
|
||||||
using L1 = std::tuple<float, double, long double>;
|
.Using mp_pop_front with std::tuple
|
||||||
using R1 = mp_pop_front<L1>; // std::tuple<double, long double>
|
```
|
||||||
|
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 mp_pop_front with mp_list
|
||||||
using R2 = mp_pop_front<L2>; // mp_list<>
|
```
|
||||||
|
using L2 = mp_list<void>;
|
||||||
|
using R2 = mp_pop_front<L2>; // mp_list<>
|
||||||
|
```
|
||||||
|
|
||||||
## mp_first<L>
|
## mp_first<L>
|
||||||
|
|
||||||
@@ -88,14 +121,23 @@ the list.
|
|||||||
|
|
||||||
`mp_second<L>` is the second element of the list `L`. That is, `mp_second<L<T1, T2, T...>>` is an alias for `T2`.
|
`mp_second<L>` is the second element of the list `L`. That is, `mp_second<L<T1, T2, T...>>` is an alias for `T2`.
|
||||||
|
|
||||||
using L1 = std::pair<int, float>;
|
.Using mp_second with std::pair
|
||||||
using R1 = mp_second<L1>; // float
|
```
|
||||||
|
using L1 = std::pair<int, float>;
|
||||||
|
using R1 = mp_second<L1>; // float
|
||||||
|
```
|
||||||
|
|
||||||
using L2 = std::tuple<float, double, long double>;
|
.Using mp_second with std::tuple
|
||||||
using R2 = mp_second<L2>; // double
|
```
|
||||||
|
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 mp_second with mp_list
|
||||||
using R3 = mp_second<L3>; // char[2]
|
```
|
||||||
|
using L3 = mp_list<char[1], char[2], char[3], char[4]>;
|
||||||
|
using R3 = mp_second<L3>; // char[2]
|
||||||
|
```
|
||||||
|
|
||||||
## mp_third<L>
|
## mp_third<L>
|
||||||
|
|
||||||
@@ -103,11 +145,17 @@ the list.
|
|||||||
|
|
||||||
`mp_third<L>` is the third element of the list `L`. That is, `mp_third<L<T1, T2, T3, T...>>` is an alias for `T3`.
|
`mp_third<L>` is the third element of the list `L`. That is, `mp_third<L<T1, T2, T3, T...>>` is an alias for `T3`.
|
||||||
|
|
||||||
using L1 = std::tuple<float, double, long double>;
|
.Using mp_third with std::tuple
|
||||||
using R1 = mp_third<L1>; // long double
|
```
|
||||||
|
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 mp_third with mp_list
|
||||||
using R2 = mp_third<L2>; // char[3]
|
```
|
||||||
|
using L2 = mp_list<char[1], char[2], char[3], char[4]>;
|
||||||
|
using R2 = mp_third<L2>; // char[3]
|
||||||
|
```
|
||||||
|
|
||||||
## mp_push_front<L, T...>
|
## mp_push_front<L, T...>
|
||||||
|
|
||||||
@@ -116,11 +164,17 @@ the list.
|
|||||||
`mp_push_front<L, T...>` inserts the elements `T...` at the front of the list `L`. That is, `mp_push_front<L<U...>, T...>`
|
`mp_push_front<L, T...>` inserts the elements `T...` at the front of the list `L`. That is, `mp_push_front<L<U...>, T...>`
|
||||||
is an alias for `L<T..., U...>`.
|
is an alias for `L<T..., U...>`.
|
||||||
|
|
||||||
using L1 = std::tuple<double, long double>;
|
.Using mp_push_front with std::tuple
|
||||||
using R1 = mp_push_front<L1, float>; // std::tuple<float, double, long double>
|
```
|
||||||
|
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 mp_push_front with mp_list
|
||||||
using R2 = mp_push_front<L2, char[1], char[2]>; // mp_list<char[1], char[2], void>
|
```
|
||||||
|
using L2 = mp_list<void>;
|
||||||
|
using R2 = mp_push_front<L2, char[1], char[2]>; // mp_list<char[1], char[2], void>
|
||||||
|
```
|
||||||
|
|
||||||
## mp_push_back<L, T...>
|
## mp_push_back<L, T...>
|
||||||
|
|
||||||
@@ -129,11 +183,17 @@ is an alias for `L<T..., U...>`.
|
|||||||
`mp_push_back<L, T...>` inserts the elements `T...` at the back of the list `L`. That is, `mp_push_back<L<U...>, T...>`
|
`mp_push_back<L, T...>` inserts the elements `T...` at the back of the list `L`. That is, `mp_push_back<L<U...>, T...>`
|
||||||
is an alias for `L<U..., T...>`.
|
is an alias for `L<U..., T...>`.
|
||||||
|
|
||||||
using L1 = std::tuple<double, long double>;
|
.Using mp_push_back with std::tuple
|
||||||
using R1 = mp_push_back<L1, float>; // std::tuple<double, long double, float>
|
```
|
||||||
|
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 mp_push_back with mp_list
|
||||||
using R2 = mp_push_back<L2, char[1], char[2]>; // mp_list<void, char[1], char[2]>
|
```
|
||||||
|
using L2 = mp_list<void>;
|
||||||
|
using R2 = mp_push_back<L2, char[1], char[2]>; // mp_list<void, char[1], char[2]>
|
||||||
|
```
|
||||||
|
|
||||||
## mp_rename<L, Y>
|
## mp_rename<L, Y>
|
||||||
|
|
||||||
@@ -141,11 +201,17 @@ is an alias for `L<U..., T...>`.
|
|||||||
|
|
||||||
`mp_rename<L, Y>` changes the type of the list `L` to `Y`. That is, `mp_rename<L<T...>, Y>` is an alias for `Y<T...>`.
|
`mp_rename<L, Y>` changes the type of the list `L` to `Y`. That is, `mp_rename<L<T...>, Y>` is an alias for `Y<T...>`.
|
||||||
|
|
||||||
using L1 = std::pair<double, long double>;
|
.Using mp_rename to rename std::pair to std::tuple
|
||||||
using R1 = mp_rename<L1, std::tuple>; // std::tuple<double, long double>
|
```
|
||||||
|
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 mp_rename to rename std::tuple to mp_list
|
||||||
using R2 = mp_rename<L2, mp_list>; // mp_list<void>
|
```
|
||||||
|
using L2 = std::tuple<void>;
|
||||||
|
using R2 = mp_rename<L2, mp_list>; // mp_list<void>
|
||||||
|
```
|
||||||
|
|
||||||
## mp_apply<F, L>
|
## mp_apply<F, L>
|
||||||
|
|
||||||
@@ -154,35 +220,45 @@ is an alias for `L<U..., T...>`.
|
|||||||
`mp_apply<F, L>` applies the metafunction `F` to the contents of the list `L`, that is, `mp_apply<F, L<T...>>` is an alias for `F<T...>`.
|
`mp_apply<F, L>` applies the metafunction `F` to the contents of the list `L`, that is, `mp_apply<F, L<T...>>` is an alias for `F<T...>`.
|
||||||
(`mp_apply` is the same as `mp_rename` with the arguments reversed.)
|
(`mp_apply` is the same as `mp_rename` with the arguments reversed.)
|
||||||
|
|
||||||
using L1 = std::pair<double, long double>;
|
.Using mp_apply with std::pair
|
||||||
using R1 = mp_apply<std::is_same, L1>; // std::is_same<double, long double>
|
```
|
||||||
|
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>
|
## mp_apply_q<Q, L>
|
||||||
|
|
||||||
template<class Q, class L> using mp_apply_q = mp_apply<Q::template fn, L>;
|
template<class Q, class L> using mp_apply_q = mp_apply<Q::template fn, L>;
|
||||||
|
|
||||||
Same as `mp_apply`, but takes a quoted metafunction.
|
Same as `mp_apply`, but takes a quoted metafunction.
|
||||||
|
|
||||||
|
.Using mp_apply_q with mp_bind_front
|
||||||
```
|
```
|
||||||
using L1 = std::tuple<double, long double>;
|
using L1 = std::tuple<double, long double>;
|
||||||
using L2 = mp_list<int, long>;
|
using L2 = mp_list<int, long>;
|
||||||
|
|
||||||
using R1 = mp_apply_q<mp_bind_front<mp_push_back, L1>, L2>;
|
using R1 = mp_apply_q<mp_bind_front<mp_push_back, L1>, L2>;
|
||||||
// R1 is std::tuple<double, long double, int, long>
|
// R1 is std::tuple<double, long double, int, long>
|
||||||
```
|
```
|
||||||
|
|
||||||
## mp_append<L...>
|
## mp_append<L...>
|
||||||
|
|
||||||
template<class... L> using mp_append = /*...*/;
|
template<class... L> using mp_append = /*...*/;
|
||||||
|
|
||||||
`mp_append<L...>` concatenates the lists in `L...` into a single list that has the same type as the first list. `mp_append<>`
|
`mp_append<L...>` concatenates the lists in `L...` into a single list that has the same type as the first list. `mp_append<>`
|
||||||
is an alias for `mp_list<>`. `mp_append<L1<T1...>, L2<T2...>, ..., Ln<Tn...>>` is an alias for `L1<T1..., T2..., ..., Tn...>`.
|
is an alias for `mp_list<>`. `mp_append<L1<T1...>, L2<T2...>, ..., Ln<Tn...>>` is an alias for `L1<T1..., T2..., ..., Tn...>`.
|
||||||
|
|
||||||
|
.Using mp_append with lists of various types
|
||||||
```
|
```
|
||||||
using L1 = std::tuple<double, long double>;
|
using L1 = std::tuple<double, long double>;
|
||||||
using L2 = mp_list<int>;
|
using L2 = mp_list<int>;
|
||||||
using L3 = std::pair<short, long>;
|
using L3 = std::pair<short, long>;
|
||||||
using L4 = mp_list<>;
|
using L4 = mp_list<>;
|
||||||
|
|
||||||
using R1 = mp_append<L1, L2, L3, L4>; // std::tuple<double, long double, int, short, long>
|
using R1 = mp_append<L1, L2, L3, L4>;
|
||||||
|
// std::tuple<double, long double, int, short, long>
|
||||||
```
|
```
|
||||||
|
|
||||||
## mp_replace_front<L, T>
|
## mp_replace_front<L, T>
|
||||||
|
|
||||||
template<class L, class T> using mp_replace_front = /*...*/;
|
template<class L, class T> using mp_replace_front = /*...*/;
|
||||||
@@ -190,14 +266,23 @@ using R1 = mp_append<L1, L2, L3, L4>; // std::tuple<double, long double, int, sh
|
|||||||
`mp_replace_front<L, T>` replaces the first element of the list `L` with `T`. That is, `mp_replace_front<L<U1, U...>, T>` is
|
`mp_replace_front<L, T>` replaces the first element of the list `L` with `T`. That is, `mp_replace_front<L<U1, U...>, T>` is
|
||||||
an alias for `L<T, U...>`.
|
an alias for `L<T, U...>`.
|
||||||
|
|
||||||
using L1 = std::pair<int, float>;
|
.Using mp_replace_front with std::pair
|
||||||
using R1 = mp_replace_front<L1, void>; // std::pair<void, float>
|
```
|
||||||
|
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 mp_replace_front with std::tuple
|
||||||
using R2 = mp_replace_front<L2, void>; // std::tuple<void, double, long double>
|
```
|
||||||
|
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 mp_replace_front with mp_list
|
||||||
using R3 = mp_replace_front<L3, void>; // mp_list<void, char[2], char[3], char[4]>;
|
```
|
||||||
|
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]>;
|
||||||
|
```
|
||||||
|
|
||||||
## mp_replace_first<L, T>
|
## mp_replace_first<L, T>
|
||||||
|
|
||||||
@@ -212,14 +297,23 @@ an alias for `L<T, U...>`.
|
|||||||
`mp_replace_second<L, T>` replaces the second element of the list `L` with `T`. That is, `mp_replace_second<L<U1, U2, U...>, T>`
|
`mp_replace_second<L, T>` replaces the second element of the list `L` with `T`. That is, `mp_replace_second<L<U1, U2, U...>, T>`
|
||||||
is an alias for `L<U1, T, U...>`.
|
is an alias for `L<U1, T, U...>`.
|
||||||
|
|
||||||
using L1 = std::pair<int, float>;
|
.Using mp_replace_second with std::pair
|
||||||
using R1 = mp_replace_second<L1, void>; // std::pair<int, void>
|
```
|
||||||
|
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 mp_replace_second with std::tuple
|
||||||
using R2 = mp_replace_second<L2, void>; // std::tuple<float, void, long double>
|
```
|
||||||
|
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 mp_replace_front with mp_list
|
||||||
using R3 = mp_replace_second<L3, void>; // mp_list<char[1], void, char[3], char[4]>;
|
```
|
||||||
|
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]>;
|
||||||
|
```
|
||||||
|
|
||||||
## mp_replace_third<L, T>
|
## mp_replace_third<L, T>
|
||||||
|
|
||||||
@@ -228,8 +322,14 @@ is an alias for `L<U1, T, U...>`.
|
|||||||
`mp_replace_third<L, T>` replaces the third element of the list `L` with `T`. That is, `mp_replace_third<L<U1, U2, U3, U...>, T>`
|
`mp_replace_third<L, T>` replaces the third element of the list `L` with `T`. That is, `mp_replace_third<L<U1, U2, U3, U...>, T>`
|
||||||
is an alias for `L<U1, U2, T, U...>`.
|
is an alias for `L<U1, U2, T, U...>`.
|
||||||
|
|
||||||
using L1 = std::tuple<float, double, long double>;
|
.Using mp_replace_third with std::tuple
|
||||||
using R1 = mp_replace_third<L1, void>; // std::tuple<float, double, void>
|
```
|
||||||
|
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 mp_replace_third with mp_list
|
||||||
using R2 = mp_replace_third<L2, void>; // mp_list<char[1], char[2], void, char[4]>;
|
```
|
||||||
|
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]>;
|
||||||
|
```
|
||||||
|
@@ -23,13 +23,15 @@ A map is a list of lists, the inner lists having at least one element (the key.)
|
|||||||
|
|
||||||
## mp_map_contains<M, K>
|
## 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>>;
|
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>` is `mp_true` if the map `M` contains an element with a key `K`, `mp_false` otherwise.
|
`mp_map_contains<M, K>` is `mp_true` if the map `M` contains an element with a key `K`, `mp_false` otherwise.
|
||||||
|
|
||||||
## mp_map_insert<M, T>
|
## 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> >;
|
template<class M, class T> using mp_map_insert =
|
||||||
|
mp_if< mp_map_contains<M, mp_first<T>>, M, mp_push_back<M, T> >;
|
||||||
|
|
||||||
Inserts the element `T` into the map `M`, if an element with a key `mp_first<T>` is not already in `M`.
|
Inserts the element `T` into the map `M`, if an element with a key `mp_first<T>` is not already in `M`.
|
||||||
|
|
||||||
|
@@ -10,8 +10,9 @@ http://www.boost.org/LICENSE_1_0.txt
|
|||||||
[#overview]
|
[#overview]
|
||||||
# Overview
|
# Overview
|
||||||
|
|
||||||
Mp11 is a C++11 metaprogramming library based on template aliases and variadic templates.
|
Mp11 is a C++11 metaprogramming library for compile-time manipulation of data structures
|
||||||
It implements the approach outlined in the article
|
that contain types. It's based on template aliases and variadic templates and implements the
|
||||||
|
approach outlined in the article
|
||||||
http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html["Simple {cpp} metaprogramming"]
|
http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html["Simple {cpp} metaprogramming"]
|
||||||
and http://pdimov.com/cpp2/simple_cxx11_metaprogramming_2.html[its sequel]. Reading these
|
and http://pdimov.com/cpp2/simple_cxx11_metaprogramming_2.html[its sequel]. Reading these
|
||||||
articles before proceeding with this documentation is _highly_ recommended.
|
articles before proceeding with this documentation is _highly_ recommended.
|
||||||
|
@@ -20,6 +20,35 @@ http://www.boost.org/LICENSE_1_0.txt
|
|||||||
using type = T;
|
using type = T;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
`mp_identity` is a simple _transformation type trait_ (as per the C++ standard)
|
||||||
|
that just returns the same type. It's useful both as such, and as a type wrapper
|
||||||
|
useful for passing types as values to functions.
|
||||||
|
|
||||||
|
.Using mp_identity as a type trait
|
||||||
|
```
|
||||||
|
template<class T> using addp_if_not_ref =
|
||||||
|
typename mp_if<std::is_reference<T>, mp_identity<T>, std::add_pointer<T>>::type;
|
||||||
|
```
|
||||||
|
|
||||||
|
.Using mp_identity to protect qualifiers and references
|
||||||
|
```
|
||||||
|
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>
|
## mp_identity_t<T>
|
||||||
|
|
||||||
template<class T> using mp_identity_t = T;
|
template<class T> using mp_identity_t = T;
|
||||||
@@ -34,33 +63,75 @@ http://www.boost.org/LICENSE_1_0.txt
|
|||||||
|
|
||||||
`mp_if_c<true, T, E...>` is an alias for `T`. `mp_if_c<false, T, E>` is an alias for `E`. Otherwise, the result is a substitution failure.
|
`mp_if_c<true, T, E...>` is an alias for `T`. `mp_if_c<false, T, E>` is an alias for `E`. Otherwise, the result is a substitution failure.
|
||||||
|
|
||||||
using R1 = mp_if_c<true, int, void>; // int
|
.Using mp_if_c to select between two alternatives
|
||||||
using R2 = mp_if_c<flase, int, void>; // void
|
```
|
||||||
|
using R1 = mp_if_c<true, int, void>; // int
|
||||||
|
|
||||||
template<class I> using void_if_5 = mp_if_c<I::value == 5, void>; // `void` when `I::value` is 5, substitution failure otherwise
|
using R2 = mp_if_c<false, int, void>; // void
|
||||||
|
```
|
||||||
|
|
||||||
|
.Using mp_if_c to fail substitution when a condition is not met
|
||||||
|
```
|
||||||
|
template<class I> using void_if_5 = mp_if_c<I::value == 5, void>;
|
||||||
|
```
|
||||||
|
This example returns `void` when `I::value` is 5, and generates a substitution failure
|
||||||
|
otherwise. It's the same as `std::enable_if_t<I::value == 5>` in {cpp}14, or
|
||||||
|
`typename std::enable_if<I::value == 5>::type` in {cpp}11.
|
||||||
|
|
||||||
## mp_if<C, T, E...>
|
## 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...>;
|
template<class C, class T, class E...> using mp_if =
|
||||||
|
mp_if_c<static_cast<bool>(C::value), T, E...>;
|
||||||
|
|
||||||
Like `mp_if_c`, but the first argument is a type.
|
Like `mp_if_c`, but the first argument is a type.
|
||||||
|
|
||||||
|
.Using mp_if to select between two alternatives
|
||||||
|
```
|
||||||
|
using R1 = mp_if<mp_true, int, void>; // int
|
||||||
|
|
||||||
|
using R2 = mp_if<mp_false, int, void>; // void
|
||||||
|
```
|
||||||
|
|
||||||
|
.Using mp_if to fail substitution when a condition is not met
|
||||||
|
```
|
||||||
|
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...>
|
## mp_eval_if_c<C, T, F, U...>
|
||||||
|
|
||||||
template<bool C, class T, template<class...> class F, class... U> using mp_eval_if_c = /*...*/;
|
template<bool C, class T, template<class...> class F, class... U> using mp_eval_if_c =
|
||||||
|
/*...*/;
|
||||||
|
|
||||||
`mp_eval_if_c<C, T, F, U...>` is an alias for `T` when `C` is `true`, for `F<U...>` otherwise. Its purpose
|
`mp_eval_if_c<C, T, F, U...>` is an alias for `T` when `C` is `true`, for `F<U...>` otherwise. Its purpose
|
||||||
is to avoid evaluating `F<U...>` when the condition is `true` as it may not be valid in this case.
|
is to avoid evaluating `F<U...>` when the condition is `true` as it may not be valid in this case.
|
||||||
|
|
||||||
|
.Using mp_eval_if_c to select the first pack element, or void
|
||||||
|
```
|
||||||
|
template<class... T> using first_or_void =
|
||||||
|
mp_eval_if_c<sizeof...(T) == 0, void, mp_apply, mp_first, mp_list<T...>>;
|
||||||
|
```
|
||||||
|
|
||||||
## mp_eval_if<C, T, F, U...>
|
## 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...>;
|
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...>;
|
||||||
|
|
||||||
Like `mp_eval_if_c`, but the first argument is a type.
|
Like `mp_eval_if_c`, but the first argument is a type.
|
||||||
|
|
||||||
|
.Using mp_eval_if to select the first list element, or void
|
||||||
|
```
|
||||||
|
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...>
|
## 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...>;
|
template<class C, class T, class Q, class... U> using mp_eval_if_q =
|
||||||
|
mp_eval_if<C, T, Q::template fn, U...>;
|
||||||
|
|
||||||
Like `mp_eval_if`, but takes a quoted metafunction.
|
Like `mp_eval_if`, but takes a quoted metafunction.
|
||||||
|
|
||||||
@@ -70,6 +141,13 @@ Like `mp_eval_if`, but takes a quoted metafunction.
|
|||||||
|
|
||||||
`mp_valid<F, T...>` is an alias for `mp_true` when `F<T...>` is a valid expression, for `mp_false` otherwise.
|
`mp_valid<F, T...>` is an alias for `mp_true` when `F<T...>` is a valid expression, for `mp_false` otherwise.
|
||||||
|
|
||||||
|
.Using mp_valid to write a metafunction that checks for the existence of a nested type
|
||||||
|
```
|
||||||
|
template<class T> using get_nested_type = typename T::type;
|
||||||
|
|
||||||
|
template<class T> struct has_nested_type: mp_valid<get_nested_type, T> {};
|
||||||
|
```
|
||||||
|
|
||||||
## mp_defer<F, T...>
|
## mp_defer<F, T...>
|
||||||
|
|
||||||
template<template<class...> class F, class... T> using mp_defer = /*...*/;
|
template<template<class...> class F, class... T> using mp_defer = /*...*/;
|
||||||
@@ -86,8 +164,33 @@ When `mp_valid<F, T...>` is `mp_true`, `mp_defer<F, T...>` is a struct with a ne
|
|||||||
|
|
||||||
`mp_quote<F>` transforms the template `F` into a type with a nested template `fn` such that `fn<T...>` returns `F<T...>`.
|
`mp_quote<F>` transforms the template `F` into a type with a nested template `fn` such that `fn<T...>` returns `F<T...>`.
|
||||||
|
|
||||||
|
.Using mp_quote to make a list of metafunctions
|
||||||
|
```
|
||||||
|
using LQ = mp_list<mp_quote<std::is_const>, mp_quote<std::is_volatile>>;
|
||||||
|
```
|
||||||
|
|
||||||
## mp_invoke<Q, T...>
|
## mp_invoke<Q, T...>
|
||||||
|
|
||||||
template<class Q, class... T> using mp_invoke = typename Q::template fn<T...>;
|
template<class Q, class... T> using mp_invoke = typename Q::template fn<T...>;
|
||||||
|
|
||||||
`mp_invoke<Q, T...>` evaluates the nested template `fn` of a quoted metafunction. `mp_invoke<mp_quote<F>, T...>` returns `F<T...>`.
|
`mp_invoke<Q, T...>` evaluates the nested template `fn` of a quoted metafunction. `mp_invoke<mp_quote<F>, T...>` returns `F<T...>`.
|
||||||
|
|
||||||
|
.Using mp_invoke to invoke a list of metafunctions, technique 1
|
||||||
|
```
|
||||||
|
using LQ = mp_list<mp_quote<std::is_const>, mp_quote<std::is_volatile>>;
|
||||||
|
|
||||||
|
template<class T> using is_const_and_volatile =
|
||||||
|
mp_all<mp_product<mp_invoke, LQ, mp_list<T>>>;
|
||||||
|
```
|
||||||
|
|
||||||
|
.Using mp_invoke to invoke a list of metafunctions, technique 2
|
||||||
|
```
|
||||||
|
template<class T> using is_const_and_volatile =
|
||||||
|
mp_all<mp_transform_q<mp_bind_back<mp_invoke, T>, LQ>>;
|
||||||
|
```
|
||||||
|
|
||||||
|
.Using mp_invoke to invoke a list of metafunctions, technique 3
|
||||||
|
```
|
||||||
|
template<class T> using is_const_and_volatile =
|
||||||
|
mp_all<mp_transform<mp_invoke, LQ, mp_fill<LQ, T>>>;
|
||||||
|
```
|
||||||
|
Reference in New Issue
Block a user