Overview
-Mp11 is a C++11 metaprogramming library for compile-time manipulation of data structures -that contain types. It’s based on template aliases and variadic templates and implements the -approach outlined in the article -"Simple C++ metaprogramming" -and its sequel. Reading these -articles before proceeding with this documentation is highly recommended.
-The general principles upon which Mp11 is built are that algorithms and metafunctions are
-template aliases of the form F<T…>
and data structures are lists of the form L<T…>
,
-with the library placing no requirements on L
. mp_list<T…>
is the built-in list type,
-but std::tuple<T…>
, std::pair<T1, T2>
and std::variant<T…>
are also perfectly
-legitimate list types, although of course std::pair<T1, T2>
, due to having exactly two elements,
-is not resizeable and will consequently not work with algorithms that need to add or remove
-elements.
Another distinguishing feature of this approach is that lists (L<T…>
) have the same form as
-metafunctions (F<T…>
) and can therefore be used as such. For example, applying std::add_pointer_t
-to the list std::tuple<int, float>
by way of mp_transform<std::add_pointer_t, std::tuple<int, float>>
-gives us std::tuple<int*, float*>
, but we can also apply mp_list
to the same tuple:
using R = mp_transform<mp_list, std::tuple<int, float>>;-
and get std::tuple<mp_list<int>, mp_list<float>>
.
Definitions
-A list is a — usually but not necessarily variadic — template class whose parameters are all types,
-for example mp_list<char[], void>
, mp_list<>
, std::tuple<int, float, char>
, std::pair<int, float>
, std::shared_ptr<X>
.
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
template<class...> using F1 = void;
-
-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
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)>; };
-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
struct N { static int constexpr value = 2; };-
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,
-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]>>;
-Examples
-Generating Test Cases
-Let’s suppose that we have written a metafunction 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;
-that ought to represent the result of an arithmetic operation on the integer types T
and U
,
-for example t + u
. We want to test whether result<T, U>
gives correct results for various combinations
-of T
and U
, so we write the function
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;
-}
-and then need to call it a substantial number of times:
-int main() -{ - test_result<char, char>(); - test_result<char, short>(); - test_result<char, int>(); - test_result<char, unsigned>(); - // ... -}-
Writing all those type combinations by hand is unwieldy, error prone, and worst of all, boring. This is -how we can leverage Mp11 to automate the task:
-#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); } );
-}
-How does it work?
-mp_product<F, L1, L2>
calls F<T1, T2>
where T1
varies over the elements of L1
and T2
varies over
-the elements of L2
, as if by executing two nested loops. It then returns a list of these results, of the same
-type as L1
.
In our case, both lists are the same std::tuple
, and F
is mp_list
, so mp_product<mp_list, L, L>
will get us
-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>>
.
We then default-construct this tuple and pass it to tuple_for_each
. tuple_for_each(tp, f)
calls f
for every
-tuple element; we use a (C++14) lambda that calls test_result
.
In pure C++11, we can’t use a lambda with an auto&&
parameter, so we’ll have to make test_result
a function object with
-a templated operator()
and pass that to tuple_for_each
directly:
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() );
-}
-Writing common_type Specializations
-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 ?:
-operator) is unsuitable.
Let’s write a common_type
specialization for two std::tuple
arguments. For that, we need a metafunction that
-applies std::common_type
to each pair of elements and gathers the results into a 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>;
-then specialize common_type
to use it:
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
-(There is no need to specialize std::common_type
for more than two arguments - it takes care of synthesizing the appropriate semantics from
-the binary case.)
The subtlety here is the use of mp_defer
. We could have defined a nested type
to common_tuple<std::tuple<T1…>, std::tuple<T2…>>
,
-and it would still have worked in all valid cases. By letting mp_defer
define type
, though, we make our specialization SFINAE-friendly.
That is, when our common_tuple
causes a substitution failure instead of a hard error, mp_defer
will not define a nested type
,
-and common_type_t
, which is defined as typename common_type<…>::type
, will also cause a substitution failure.
As another example, consider the hypothetical type expected<T, E…>
that represents either a successful return with a value of T
,
-or an unsucessful return with an error code of some type in the list E…
. The common type of expected<T1, E1, E2, E3>
and
-expected<T2, E1, E4, E5>
is expected<common_type_t<T1, T2>, E1, E2, E3, E4, E5>
. That is, the possible return values are
-combined into their common type, and we take the union of the set of error types.
Therefore,
-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
-Here we’ve taken a different tack; instead of passing the expected
types to common_expected
, we’re passing the T
types and lists of
-the E
types. This makes our job easier. mp_unique<mp_append<E1, E2>>
gives us the concatenation of E1
and E2
with the duplicates
-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
.
Fixing tuple_cat
-The article Simple C++11 metaprogramming builds an
-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 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)... ) );
-}
-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:
std::tuple<std::unique_ptr<int>> t1;
-std::tuple<std::unique_ptr<float>> t2;
-
-auto result = ::tuple_cat( std::move( t1 ), std::move( t2 ) );
-Trying to concatenate const
tuples fails:
std::tuple<int> const t1;
-std::tuple<float> const t2;
-
-auto result = ::tuple_cat( t1, t2 );
-And finally, the standard tuple_cat
is specified to work on arbitrary tuple-like types (that is, all types
-that support tuple_size
, tuple_element
, and get
), while our implementation only works with tuple
and
-pair
. std::array
, for example, fails:
std::array<int, 2> t1{ 1, 2 };
-std::array<float, 3> t2{ 3.0f, 4.0f, 5.0f };
-
-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
-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
-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:
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)))... }; -}-
Next, const
-qualified tuples. The issue here is that we’re stripping references from the input tuples, but not
-const
. As a result, we’re trying to manipulate types such as tuple<int> const
with Mp11 algorithms, and these
-types do not fit the list concept. We just need to strip qualifiers as well, by defining the useful remove_cv_ref
-primitive that is inexplicably missing from the standard library:
template<class T> using remove_cv_ref = typename std::remove_cv< - typename std::remove_reference<T>::type>::type;-
and then by using remove_cv_ref<Tp>
in place of 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>...>;
-
- // ...
-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
-define a metafunction from_tuple_like
that will take an arbitrary tuple-like type and will return, in our case,
-the corresponding mp_list
.
Technically, a more principled approach would’ve been to return std::tuple
, but here mp_list
will prove more
-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,
-…, 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 =
- 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>
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
,
-applying F
to the two variables and gathering the result. In our case L1
consists of the single element T
, so
-only the second loop (over mp_iota<N>
, where N
is tuple_size<T>
), remains, and we get a list of the same type
-as L1
(an mp_list
) with contents tuple_element<T, mp_size_t<0>>
, tuple_element<T, mp_size_t<1>>
, …,
-tuple_element<T, mp_size_t<N-1>>
.
For completeness’s sake, here’s another, more traditional way to achieve the same result:
-template<class T> using from_tuple_like = - 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:
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)... ) );
-}
-Computing Return Types
-C++17 has a standard variant type, called std::variant
. It also defines a function template
-std::visit
that can be used to apply a function to the contained value of one or more variants.
-So for instance, if the variant v1
contains 1
, and the variant v2
contains 2.0f
,
-std::visit(f, v1, v2)
will call f(1, 2.0f)
.
However, std::visit
has one limitation: it cannot return a result unless all
-possible applications of the function have the same return type. If, for instance, v1
and v2
-are both of type std::variant<short, int, float>
,
std::visit( []( auto const& x, auto const& y ){ return x + y; }, v1, v2 );-
will fail to compile because the result of x + y
can be either int
or float
depending on
-what v1
and v2
hold.
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
:
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 )... );
-}
-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
-calling f
with all possible combinations of variant values.
We’ll first define a helper quoted metafunction Qret<F>
that returns the result of the application of F
to arguments of type T…
:
template<class F> struct Qret -{ - 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.)
With Qret
in hand, a variant
of the possible return types is just a matter of applying it over the possible combinations of the variant values:
using R = mp_product_q<Qret<F>, std::remove_reference_t<V>...>;-
Why does this work? mp_product<F, L1<T1…>, L2<T2…>, …, Ln<Tn…>>
returns L1<F<U1, U2, …, Un>, …>
, where Ui
traverse all
-possible combinations of list values. Since in our case all Li
are std::variant
, the result will also be std::variant
. (mp_product_q
is
-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
-[]( 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, we pass the result to mp_unique
:
using R = mp_unique<mp_product_q<Qret<F>, std::remove_reference_t<V>...>>;-
and we’re done:
-#include <boost/mp11.hpp>
-#include <boost/core/demangle.hpp>
-#include <variant>
-#include <type_traits>
-#include <typeinfo>
-#include <iostream>
-
-using namespace boost::mp11;
-
-template<class F> struct Qret
-{
- template<class... T> using fn =
- decltype( std::declval<F>()( std::declval<T>()... ) );
-};
-
-template<class F, class... V> auto rvisit( F&& f, V&&... v )
-{
- using R = mp_unique<mp_product_q<Qret<F>, std::remove_reference_t<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> 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 );
-}
-Reference
-The contents of the library are in namespace boost::mp11
.
Integral Constants, <boost/mp11/integral.hpp>
-For an Mp11 integral constant type T
, T::value
is an integral constant in the C++ sense.
mp_bool<B>
-template<bool B> using mp_bool = std::integral_constant<bool, B>;-
Same as std::bool_constant
in C++17.
mp_true
-using mp_true = mp_bool<true>;-
Same as std::true_type
.
mp_false
-using mp_false = mp_bool<false>;-
Same as 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>;-
List Operations, <boost/mp11/list.hpp>
-mp_list<T…>
-template<class... T> struct mp_list {};-
mp_list
is the standard list type of Mp11, although the library is not restricted to it and can operate on arbitrary class templates
-such as std::tuple
or std::variant
. Even std::pair
can be used if the transformation does not alter the number of the elements in
-the list.
mp_size<L>
-template<class L> using mp_size = /*...*/;-
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)>
.
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>
-mp_empty<L>
-template<class L> using mp_empty = mp_bool<mp_size<L>::value == 0>;-
mp_empty<L>
is an alias for mp_true
if the list L
is empty, for mp_false
otherwise.
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>
-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
.
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]
-mp_pop_front<L>
-template<class L> using mp_pop_front = /*...*/;-
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 R1 = mp_pop_front<L1>; // std::tuple<double, long double>
-using L2 = mp_list<void>;
-using R2 = mp_pop_front<L2>; // mp_list<>
-mp_first<L>
-template<class L> using mp_first = mp_front<L>;-
mp_first
is another name for mp_front
.
mp_rest<L>
-template<class L> using mp_rest = mp_pop_front<L>;-
mp_rest
is another name for mp_pop_front
.
mp_second<L>
-template<class L> using mp_second = /*...*/;-
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 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]
-mp_third<L>
-template<class L> using mp_third = /*...*/;-
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 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]
-mp_push_front<L, T…>
-template<class L, class... T> using mp_push_front = /*...*/;-
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…>
.
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>
-mp_push_back<L, T…>
-template<class L, class... T> using mp_push_back = /*...*/;-
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…>
.
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]>
-mp_rename<L, Y>
-template<class L, template<class...> class Y> using mp_rename = /*...*/;-
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 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>
-mp_apply<F, L>
-template<template<class...> class F, class L> using mp_apply = mp_rename<L, F>;-
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.)
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>;-
Same as mp_apply
, but takes a quoted metafunction.
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_append<L…>
-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<>
-is an alias for mp_list<>
. mp_append<L1<T1…>, L2<T2…>, …, Ln<Tn…>>
is an alias for L1<T1…, T2…, …, Tn…>
.
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>
-mp_replace_front<L, T>
-template<class L, class T> using mp_replace_front = /*...*/;-
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…>
.
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]>;
-mp_replace_first<L, T>
-template<class L, class T> using mp_replace_first = mp_replace_front<L, T>;-
mp_replace_first
is another name for mp_replace_front
.
mp_replace_second<L, T>
-template<class L, class T> using mp_replace_second = /*...*/;-
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…>
.
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]>;
-mp_replace_third<L, T>
-template<class L, class T> using mp_replace_third = /*...*/;-
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…>
.
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]>;
-Utility Components, <boost/mp11/utility.hpp>
-mp_identity<T>
-template<class T> struct mp_identity -{ - 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.
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…>
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 R2 = mp_if_c<false, int, void>; // void
-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 C++14, or
-typename std::enable_if<I::value == 5>::type
in C++11.
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...>;-
Like mp_if_c
, but the first argument is a type.
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…>
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.
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…>
-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.
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...>;-
Like mp_eval_if
, but takes a quoted metafunction.
mp_valid<F, T…>
-template<template<class...> class F, class... T> using mp_valid = /*...*/;-
mp_valid<F, T…>
is an alias for mp_true
when F<T…>
is a valid expression, for mp_false
otherwise.
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…>
-template<template<class...> class F, class... T> using mp_defer = /*...*/;-
When mp_valid<F, T…>
is mp_true
, mp_defer<F, T…>
is a struct with a nested type type
which is an alias for F<T…>
. Otherwise,
-mp_defer<F, T…>
is an empty struct.
mp_quote<F>
-template<template<class...> class F> struct mp_quote -{ - template<class... T> using fn = 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 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>
transforms the C++03-style trait F
into a quoted metafunction.
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, 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…>
.
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>>>;
-template<class T> using is_const_and_volatile =
- mp_all<mp_transform_q<mp_bind_back<mp_invoke, T>, LQ>>;
-template<class T> using is_const_and_volatile =
- mp_all<mp_transform<mp_invoke, LQ, mp_fill<LQ, T>>>;
-Algorithms, <boost/mp11/algorithm.hpp>
-mp_assign<L1, L2>
-template<class L1, class L2> using mp_assign = /*...*/;-
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 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>
-
|
-
|
-
|
-
|
-
|
-
- | ||||
|
-
|
-
|
-
|
-
|
-
- | ||||
|
-
|
-
|
-
|
-
|
-
mp_clear<L>
-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
.
using L1 = std::tuple<int, float>;
-using R1 = mp_clear<L1>; // std::tuple<>
-mp_transform<F, L…>
-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>…>
.
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_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_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...>;-
As mp_transform
, but takes a quoted metafunction.
void
in a listusing 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>
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
.
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...>;-
As mp_transform_if
, but takes quoted metafunctions.
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>
-template<class L, class V> using mp_fill = /*...*/;-
mp_fill<L<T…>, V>
returns L<V, V, …, V>
, with the result having the same size as the input.
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>
-
|
-
|
-
|
-
|
-
|
-
- | ||||
|
-
|
-
|
-
|
-
|
-
mp_count<L, V>
-template<class L, class V> using mp_count = /*...*/;-
mp_count<L, V>
returns mp_size_t<N>
, where N
is the number of elements of L
same as V
.
mp_count_if<L, P>
-template<class L, template<class...> class P> using mp_count_if = /*...*/;-
mp_count_if<L, P>
returns mp_size_t<N>
, where N
is the number of elements T
of L
for which mp_to_bool<P<T>>
is mp_true
.
mp_contains<L, V>
-template<class L, class V> using mp_contains = mp_to_bool<mp_count<L, V>>;-
mp_contains<L, V>
is mp_true
when L
contains an element V
, mp_false
otherwise.
mp_repeat_c<L, N>
-template<class L, std::size_t N> using mp_repeat_c = /*...*/;-
mp_repeat_c<L, N>
returns a list of the same type as L
that consists of N
concatenated copies of L
.
mp_repeat<L, N>
-template<class L, class N> using mp_repeat = /*...*/;-
Same as mp_repeat_c
but with a type argument N
. The number of copies is N::value
and must be nonnegative.
mp_product<F, L…>
-template<template<class...> class F, class... L> using mp_product = /*...*/;-
mp_product<F, L1<T1…>, L2<T2…>, …, Ln<Tn…>>
evaluates F<U1, U2, …, Un>
for values Ui
taken from
-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
.
|
-
|
-
|
-
|
-
|
-
- | ||||
|
-
|
-
|
-
|
-
|
-
- | ||||
|
-
|
-
|
-
|
-
|
-
- |
|
-
|
-
|
-
|
-
- |
|
-|||
- |
|
-
|
-
|
-
|
-
mp_product_q<Q, L…>
-template<class Q, class... L> using mp_product_q = mp_product<Q::template fn, L...>;-
As mp_product
, but takes a quoted metafunction.
mp_drop_c<L, N>
-template<class L, std::size_t N> using mp_drop_c = /*...*/;-
mp_drop_c<L, N>
removes the first N
elements of L
and returns the result.
|
-
|
-
|
-
|
-
|
-
|
-
|
-
- | ||||||
|
-
|
-
|
-
|
-- |
mp_drop<L, N>
-template<class L, class N> using mp_drop = /*...*/;-
Same as mp_drop_c
, but with a type argument N
. N::value
must be a nonnegative number.
mp_iota_c<N>
-template<std::size_t N> using mp_iota_c = /*...*/;-
mp_iota_c<N>
is an alias for mp_list<mp_size_t<0>, mp_size_t<1>, …, mp_size_t<N-1>>
.
mp_iota<N>
-template<class N> using mp_iota = /*...*/;-
Same as mp_iota_c
, but with a type argument N
. N::value
must be a nonnegative number. Returns
-mp_list<std::integral_constant<T, 0>, std::integral_constant<T, 1>, …, std::integral_constant<T, N::value-1>>
-where T
is the type of N::value
.
|
-
|
-
|
-
|
-
|
-
mp_at_c<L, I>
-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<L, I>
-template<class L, class I> using mp_at = /*...*/;-
Same as mp_at_c
, but with a type argument I
. I::value
must be a nonnegative number.
mp_take_c<L, N>
-template<class L, std::size_t N> using mp_take_c = /*...*/;-
mp_take_c<L, N>
returns a list of the same type as L
containing the first N
elements of L
.
|
-
|
-
|
-
|
-
|
-
|
-
|
-
- | ||||||
|
-
|
-
|
-
|
-- |
mp_take<L, N>
-template<class L, class N> using mp_take = /*...*/;-
Same as mp_take_c
, but with a type argument N
. N::value
must be a nonnegative number.
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...>>;-
Inserts the elements T…
into the list L
at position I
(a zero-based index).
|
-
|
-
|
-
|
-
|
-
|
-
|
-- | |
- | ||||||||
|
-
|
-
|
-
|
-
|
-
|
-
|
-
|
-
|
-
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...>>;-
Same as mp_insert_c
, but with a type argument 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>>;-
Removes from the list L
the elements with indices from I
(inclusive) to J
(exclusive).
|
-
|
-
|
-
|
-
|
-
|
-
|
-
|
-
|
-
|
-
- | |||||||||
|
-
|
-
|
-
|
-
|
-
|
-
|
-- |
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>>;-
Same as mp_erase_c
, but with a type arguments I
and J
.
mp_replace<L, V, W>
-template<class L, class V, class W> using mp_replace = /*...*/;-
Replaces all V
elements of L
with W
and returns the result.
|
-
|
-
|
-
|
-
|
-
- | ||||
|
-
|
-
|
-
|
-
|
-
mp_replace_if<L, P, W>
-template<class L, template<class...> class P, class W> using mp_replace_if = /*...*/;-
Replaces all T
elements of L
for which mp_to_bool<P<T>>
is mp_true
with W
and returns the result.
|
-
|
-
|
-
|
-
|
-
- | ||||
|
-
|
-
|
-
|
-
|
-
- | ||||
|
-
|
-
|
-
|
-
|
-
mp_replace_at_c<L, I, W>
-template<class L, std::size_t I, class W> using mp_replace_at_c = /*...*/;-
Replaces the element of L
at zero-based index I
with W
and returns the result.
mp_replace_at<L, I, W>
-template<class L, class I, class W> using mp_replace_at = /*...*/;-
Same as mp_replace_at_c
, but with a type argument I
. I::value
must be a nonnegative number.
mp_copy_if<L, P>
-template<class L, template<class...> class P> using mp_copy_if = /*...*/;-
Copies the elements T
of L
for which mp_to_bool<P<T>>
is mp_true
to a new list of the same type and returns it.
mp_remove<L, V>
-template<class L, class V> using mp_remove = /*...*/;-
Removes all V
elements of L
and returns the result.
mp_remove_if<L, P>
-template<class L, template<class...> class P> using mp_remove_if = /*...*/;-
Removes all elements T
of L
for which mp_to_bool<P<T>>
is mp_true
and returns the result.
mp_partition<L, P>
-template<class L, template<class...> class P> using mp_partition = /*...*/;-
mp_partition<L<T…>, P>
partitions L
into two lists L<U1…>
and L<U2…>
such that mp_to_bool<P<T>>
is mp_true
-for the elements of L<U1…>
and mp_false
for the elements of L<U2…>
. Returns L<L<U1…>, L<U2…>>
.
mp_sort<L, P>
-template<class L, template<class...> class P> using mp_sort = /*...*/;-
mp_sort<L, P>
sorts the list L
according to the strict weak ordering mp_to_bool<P<T, U>>
.
#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>
-template<class L, class V> using mp_find = /*...*/;-
mp_find<L, V>
returns the index at which the type V
is located in the list L
. It’s an alias for mp_size_t<I>
,
-where I
is the zero-based index of the first occurence of V
in L
. If L
does not contain V
, mp_find<L, V>
-is mp_size<L>
.
mp_find_if<L, P>
-template<class L, template<class...> class P> using mp_find_if = /*...*/;-
mp_find_f<L, P>
is an alias for mp_size_t<I>
, where I
is the zero-based index of the first element T
in L
for which
-mp_to_bool<P<T>>
is mp_true
. If there is no such element, mp_find_if<L, P>
is mp_size<L>
.
mp_reverse<L>
-template<class L> using mp_reverse = /*...*/;-
mp_reverse<L<T1, T2, …, Tn>>
is 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>
is F< F< F< F<V, T1>, T2>, …>, Tn>
, or V
, if L
is empty.
#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_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>
is F<T1, F<T2, F<…, F<Tn, V>>>>
, or V
, if L
is empty.
mp_unique<L>
-template<class L> using mp_unique = /*...*/;-
mp_unique<L>
returns a list of the same type as L
with the duplicate elements removed.
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>
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>
-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_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>
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_for_each<L>(f)
-template<class L, class F> constexpr F mp_for_each(F&& f);-
mp_for_each<L>(f)
calls f
with T()
for each element T
of the list L
, in order.
Returns 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;
-
- });
-}
-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)
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> - 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)
.
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;
-
- });
-}
-Set Operations, <boost/mp11/set.hpp>
-A set is a list whose elements are unique.
-mp_is_set<S>
-template<class S> using mp_is_set = /*...*/;-
mp_is_set<S>
is mp_true
if S
is a set, mp_false
otherwise.
mp_set_contains<S, V>
-template<class S, class V> using mp_set_contains = /*...*/;-
mp_set_contains<S, V>
is mp_true
if the type V
is an element of the set S
, mp_false
otherwise.
mp_set_push_back<S, T…>
-template<class S, class... T> using mp_set_push_back = /*...*/;-
For each T1
in T…
, mp_set_push_back<S, T…>
appends T1
to the end of S
if it’s not already an element of S
.
mp_set_push_front<S, T…>
-template<class S, class... T> using mp_set_push_front = /*...*/;-
mp_set_push_front<S, T…>
inserts at the front of S
those elements of T…
for which S
does not already contain the same type.
Map Operations, <boost/mp11/map.hpp>
-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.
-mp_is_map<M>
-template<class M> using mp_is_map = /*...*/;-
mp_is_map<M>
is mp_true
if M
is a map, mp_false
otherwise.
mp_map_find<M, K>
-template<class M, class K> using mp_map_find = /*...*/;-
mp_map_find<M, K>
is an alias for the element of the map M
with a key K
, or for void
, if there is no such element.
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>
is mp_true
if the map M
contains an element with a key K
, mp_false
otherwise.
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> >;-
Inserts the element T
into the map M
, if an element with a key mp_first<T>
is not already in M
.
mp_map_replace<M, T>
-template<class M, class T> using mp_map_replace = /*...*/;-
If the map M
does not contain an element with a key mp_first<T>
, inserts it (using mp_push_back<M, T>
); otherwise,
-replaces the existing element with T
.
mp_map_update<M, T, F>
-template<class M, class T, template<class...> class F> using mp_map_update = /*...*/;-
If the map M
does not contain an element with a key mp_first<T>
, inserts it (using mp_push_back<M, T>
); otherwise,
-replaces the existing element L<X, Y…>
with L<X, F<X, Y…>>
.
mp_map_erase<M, K>
-template<class M, class K> using mp_map_erase = /*...*/;-
If the map M
contains an element with a key K
, removes it.
mp_map_keys<M>
-template<class M> using mp_map_keys = mp_transform<mp_first, M>;-
mp_map_keys<M>
returns a list of the keys of M
. When M
is a valid map, the keys are unique, so the result is a set.
Helper Metafunctions, <boost/mp11/function.hpp>
-mp_void<T…>
-template<class... T> using mp_void = void;-
Same as std::void_t
from C++17.
mp_and<T…>
-template<class... T> using mp_and = /*...*/;-
mp_and<T…>
applies mp_to_bool
to the types in T…
, in order. If the result of an application is mp_false
, mp_and
-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
.
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 = /*...*/;-
mp_all<T…>
is mp_true
if mp_to_bool<U>
is mp_true
for all types U
in T…
, mp_false
otherwise. Same as
-mp_and
, but does not perform short-circuit evaluation. mp_and<mp_false, void>
is mp_false
, but mp_all<mp_false, void>
-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.
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…>
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
.
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 = /*...*/;-
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.
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 = /*...*/;-
mp_same<T…>
is mp_true
if all the types in T…
are the same type, mp_false
otherwise. mp_same<>
is mp_true
.
mp_plus<T…>
-template<class... T> using mp_plus = /*...*/;-
mp_plus<T…>
is an integral constant type with a value that is the sum of U::value
for all types U
in T…
.
-mp_plus<>
is mp_int<0>
.
Bind, <boost/mp11/bind.hpp>
-mp_arg<I>
-template<std::size_t I> struct mp_arg;-
mp_arg<I>
is a quoted metafunction whose nested template fn<T…>
returns the I
-th zero-based element of T…
.
_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
to _9
are placeholder types, the equivalent to the placeholders of boost::bind
.
mp_bind<F, T…>
-template<template<class...> class F, class... T> struct mp_bind;-
mp_bind<F, T…>
is a quoted metafunction that implements the type-based equivalent of boost::bind
. Its nested
-template fn<U…>
returns F<V…>
, where V…
is T…
with the placeholders replaced by the corresponding element
-of U…
and the mp_bind
expressions replaced with their corresponding evaluations against U…
.
For example, mp_bind<F, int, _2, mp_bind<G, _1>>::fn<float, void>
is 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...>;-
As mp_bind
, but takes a quoted metafunction.
mp_bind_front<F, T…>
-template<template<class...> class F, class... T> struct mp_bind_front;-
mp_bind_front<F, T…>
binds the leftmost arguments of F
to T…
. Its nested template fn<U…>
returns 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...>;-
As mp_bind_front
, but takes a quoted metafunction.
mp_bind_back<F, T…>
-template<template<class...> class F, class... T> struct mp_bind_back;-
mp_bind_back<F, T…>
binds the rightmost arguments of F
to T…
. Its nested template fn<U…>
returns 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...>;-
As mp_bind_back
, but takes a quoted metafunction.
Integer Sequences, <boost/mp11/integer_sequence.hpp>
-integer_sequence<T, I…>
-template<class T, T... I> struct integer_sequence -{ -};-
integer_sequence<T, I…>
holds a sequence of integers of type T
. Same as C++14’s std::integer_sequence
.
make_integer_sequence<T, N>
-template<class T, T N> using make_integer_sequence = /*...*/;-
make_integer_sequence<T, N>
is integer_sequence<T, 0, 1, …, N-1>
. Same as C++14’s std::make_integer_sequence
.
index_sequence<I…>
-template<std::size_t... I> using index_sequence = integer_sequence<std::size_t, I...>;-
index_sequence<I…>
is an alias for integer_sequence<size_t, I…>
. Same as C++14’s 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>
is index_sequence<0, 1, …, N-1>
. Same as C++14’s 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>
is make_index_sequence<sizeof…(T)>
. Same as C++14’s std::index_sequence_for
.
Tuple Operations, <boost/mp11/tuple.hpp>
-tuple_apply(f, tp)
-template<class F, class Tp> constexpr /*...*/ tuple_apply(F&& f, Tp&& tp);-
tuple_apply(f, tp)
returns std::forward<F>(f)(std::get<J>(std::forward<Tp>(tp))…)
for J
in 0..N-1
,
-where N
is std::tuple_size<typename std::remove_reference<Tp>::type>::value
. Same as std::apply
in C++17.
construct_from_tuple<T>(tp)
-template<class T, class Tp> T construct_from_tuple(Tp&& tp);-
construct_from_tuple<T>(tp)
returns T(std::get<J>(std::forward<Tp>(tp))…)
for J
in 0..N-1
,
-where N
is std::tuple_size<typename std::remove_reference<Tp>::type>::value
. Same as std::make_from_tuple
in C++17.
-The name of the function doesn’t match the C++17 one to avoid ambiguities when both are visible or in unqualified calls.
tuple_for_each(tp, f)
-template<class Tp, class F> constexpr F tuple_for_each(Tp&& tp, F&& f);-
tuple_for_each(tp, f)
applies the function object f
to each element of tp
by evaluating the
-expression f(std::get<J>(std::forward<Tp>(tp)))
for J
in 0..N-1
, where N
is std::tuple_size<typename std::remove_reference<Tp>::type>::value
.
Returns std::forward<F>(f)
.
Convenience Header, <boost/mp11.hpp>
-The convenience header <boost/mp11.hpp>
includes all of the
-headers listed previously in this reference.
MPL Support, <boost/mp11/mpl.hpp>
-The header <boost/mp11/mpl.hpp>
, when included, defines the
-necessary support infrastructure for mp_list
and std::tuple
-to be valid MPL sequences.
- Note
- |
-
-mpl.hpp is not included by <boost/mp11.hpp> .
- |
-
Appendix A: Copyright and License
-This documentation is
--
-
-
-
Copyright 2017 Peter Dimov
-
- -
-
Copyright 2017 Bjørn Reese
-
-
and is distributed under the Boost Software License, Version 1.0.
-