//// Copyright 2017-2019 Peter Dimov Distributed under the Boost Software License, Version 1.0. See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt //// [#algorithm] # Algorithms, :toc: :toc-title: :idprefix: ## mp_transform template class F, class... L> using mp_transform = /*...*/; `mp_transform, L2, ..., Ln>` applies `F` to each successive tuple of elements and returns `L1...>`. .Using mp_transform to produce a list of pointers from a list of pointees ``` template using add_pointer_t = typename std::add_pointer::type; // std::add_pointer_t in C++14 using L1 = std::tuple; using R1 = mp_transform; // std::tuple ``` .Using mp_transform to compare the contents of two lists of types ``` using L1 = std::tuple; using L2 = mp_list; using R1 = mp_apply>; // mp_true ``` .Using mp_transform to compare the contents of two lists of integral constants ``` template using eq = mp_bool; using L1 = std::tuple, mp_int<2>, mp_int<3>>; using L2 = mp_list, mp_size_t<2>, mp_size_t<3>>; using R1 = mp_apply>; // mp_true ``` .mp_transform on one list [cols="<.^4m,4*^.^1m",width=85%] |=== |*L1*|A~1~|A~2~|...|A~n~ 5+| |*mp_transform*|F|F|...|F |=== .mp_transform on two lists [cols="<.^4m,4*^.^1m",width=85%] |=== |*L1*|A~1~|A~2~|...|A~n~ 5+| |*L2*|B~1~|B~2~|...|B~n~ 5+| |*mp_transform*|F|F|...|F |=== ## mp_transform_q template using mp_transform_q = mp_transform; As `mp_transform`, but takes a quoted metafunction. .Using mp_transform_q to count the occurrences of `void` in a list ``` using L1 = std::tuple; using R1 = mp_apply, L1>>; // mp_int\<2> ``` [cols="<.^4m,4*^.^1m",width=85%] .mp_transform_q on two lists |=== |*L1*|A~1~|A~2~|...|A~n~ 5+| |*L2*|B~1~|B~2~|...|B~n~ 5+| |*mp_transform_q*|Q::fn|Q::fn|...|Q::fn |=== ## mp_transform_if template class P, template class F, class... L> using mp_transform_if = /*...*/; `mp_transform_if` replaces the elements of the list `L1` for which `mp_to_bool>` is `mp_true` with `F`, and returns the result, where `Ti` are the corresponding elements of `Li`. .Using mp_transform_if to replace the occurrences of 'void' in a list with the corresponding elements of a second list ``` using L1 = std::tuple; using L2 = std::tuple; template using first_is_void = std::is_same; template using second = T2; using R1 = mp_transform_if; // std::tuple ``` .mp_transform_if [cols="<.^4m,4*^.^1m",width=85%] |=== |*L1*|A~1~|A~2~|...|A~n~ 5+| |*L2*|B~1~|B~2~|...|B~n~ 5+| |*P*|mp_false|mp_true|...|mp_false 5+| |*mp_transform_if*|A~1~|F|...|A~n~ |=== ## mp_transform_if_q template using mp_transform_if_q = mp_transform_if; As `mp_transform_if`, but takes quoted metafunctions. .Using mp_transform_if_q to replace the occurrences of 'void' in a list with the corresponding elements of a second list ``` using L1 = std::tuple; using L2 = std::tuple; using R1 = mp_transform_if_q, _2, L1, L2>; // std::tuple ``` .mp_transform_if_q [cols="<.^4m,4*^.^1m",width=85%] |=== |*L1*|A~1~|A~2~|...|A~n~ 5+| |*L2*|B~1~|B~2~|...|B~n~ 5+| |*Qp::fn*|mp_false|mp_true|...|mp_false 5+| |*mp_transform_if_q*|A~1~|B~2~|...|A~n~ |=== ## mp_filter template class P, class... L> using mp_filter = /*...*/; `mp_filter` removes the elements of the list `L1` for which `mp_to_bool>` is `mp_false` and returns the result, where `Ti` are the corresponding elements of `Li`. See also `mp_copy_if` and `mp_remove_if`, less general variants of `mp_filter` that only take a single list. ## mp_filter_q template using mp_filter_q = mp_filter; As `mp_filter`, but takes a quoted metafunction. .Using mp_filter_q to pick elements of a list based on a mask in another list ``` using L1 = std::tuple; using L2 = mp_list; using R1 = mp_filter_q<_2, L1, L2>; // std::tuple ``` ## mp_fill template using mp_fill = /*...*/; `mp_fill, V>` returns `L`, with the result having the same size as the input. .Using mp_fill with std::tuple ``` using L1 = std::tuple; using R1 = mp_fill; // std::tuple ``` .Using mp_fill with std::pair ``` using L1 = std::pair; using R1 = mp_fill; // std::pair ``` .mp_fill [cols="<.^4m,4*^.^1m",width=85%] |=== |*L1*|A~1~|A~2~|...|A~n~ 5+| |*mp_fill*|V|V|...|V |=== ## mp_count template using mp_count = /*...*/; `mp_count` returns `mp_size_t`, where `N` is the number of elements of `L` same as `V`. ## mp_count_if template class P> using mp_count_if = /*...*/; `mp_count_if` returns `mp_size_t`, where `N` is the number of elements `T` of `L` for which `mp_to_bool>` is `mp_true`. ## mp_count_if_q template using mp_count_if_q = mp_count_if; As `mp_count_if`, but takes a quoted metafunction. ## mp_contains template using mp_contains = mp_to_bool>; `mp_contains` is `mp_true` when `L` contains an element `V`, `mp_false` otherwise. ## mp_starts_with template using mp_starts_with = /*...*/; `mp_starts_with` is `mp_true` when `L1` starts with `L2`, `mp_false` otherwise. ## mp_repeat_c template using mp_repeat_c = /*...*/; `mp_repeat_c` returns a list of the same form as `L` that consists of `N` concatenated copies of `L`. .Using mp_repeat_c ``` using L1 = tuple; using R1 = mp_repeat_c; // tuple using L2 = pair; using R2 = mp_repeat_c; // pair using L3 = mp_list; using R3 = mp_repeat_c; // mp_list using L4 = mp_list; using R4 = mp_repeat_c; // mp_list<> ``` ## mp_repeat template 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 template class F, class... L> using mp_product = /*...*/; `mp_product, L2, ..., Ln>` evaluates `F` 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 the form `L1` containing the results of the application of `F`. The degenerate case of zero lists, `mp_product`, returns `mp_list>`. .mp_product on two lists [cols="<.^4m,4*^.^1m",width=85%] |=== |*L1*|A~1~|A~2~|...|A~n~ 5+| |*L2*|B~1~|B~2~|...|B~m~ 5+| |*mp_product*|F|F|...|F ||F|F|...|F | 4+|... ||F|F|...|F |=== ## mp_product_q template using mp_product_q = mp_product; As `mp_product`, but takes a quoted metafunction. ## mp_power_set template using mp_power_set = /*...*/; `mp_power_set` returns a list (of the same form as `L`) of all possible 2^n^ subsets of `L` (where `n` is the length of `L`.) `mp_power_set>` returns `L>`. `mp_power_set>` returns `L, L>`. `mp_power_set>` returns `L, L, L, L>`. `mp_power_set>` returns the concatenation of `mp_power_set>` and that same list with `T1` prepended to each element. ## mp_drop_c template using mp_drop_c = /*...*/; `mp_drop_c` removes the first `N` elements of `L` and returns the result. .mp_drop_c [cols="<.^4m,6*^.^1m",width=85%] |=== |*L1*|A~1~|...|A~m~|A~m+1~|...|A~n~ 7+| |*mp_drop_c*|A~m+1~|...|A~n~ 3+| |=== ## mp_drop template using mp_drop = /*...*/; Same as `mp_drop_c`, but with a type argument `N`. `N::value` must be a nonnegative number. ## mp_from_sequence template using mp_from_sequence = /*...*/ `mp_from_sequence` transforms an integer sequence produced by `make_integer_sequence` into an `mp_list` of the corresponding `std::integral_constant` types. Given template struct S; `mp_from_sequence>` is an alias for `mp_list...>`. ## mp_iota_c template using mp_iota_c = /*...*/; `mp_iota_c` is an alias for `mp_list, mp_size_t<1>, ..., mp_size_t>`. ## mp_iota template 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, ..., std::integral_constant>` where `T` is the type of `N::value`. .mp_iota [cols="<.^4m,4*^.^1m",width=85%] |=== |*mp_iota>*|mp_int<0>|mp_int<1>|mp_int<2>|mp_int<3> |=== ## mp_at_c template using mp_at_c = /*...*/; `mp_at_c` returns the `I`-th element of `L`, zero-based. ## mp_at template using mp_at = /*...*/; Same as `mp_at_c`, but with a type argument `I`. `I::value` must be a nonnegative number. ## mp_take_c template using mp_take_c = /*...*/; `mp_take_c` returns a list of the same form as `L` containing the first `N` elements of `L`. .mp_take_c [cols="<.^4m,6*^.^1m",width=85%] |=== |*L1*|A~1~|...|A~m~|A~m+1~|...|A~n~ 7+| |*mp_take_c*|A~1~|...|A~m~ 3+| |=== ## mp_take template using mp_take = /*...*/; Same as `mp_take_c`, but with a type argument `N`. `N::value` must be a nonnegative number. ## mp_back template using mp_back = mp_at_c::value - 1>; `mp_back` returns the last element of the list `L`. ## mp_pop_back template using mp_pop_back = mp_take_c::value - 1>; `mp_pop_back` removes the last element of the list `L` and returns the result. ## mp_insert_c template using mp_insert_c = mp_append, mp_push_front, T...>>; Inserts the elements `T...` into the list `L` at position `I` (a zero-based index). .mp_insert_c with two elements [cols="<.^4m,8*^.^1m",width=85%] |=== |*L1*|A~1~|...|A~m~|A~m+1~|...|A~n~ 2+| 9+| |*mp_insert_c*|A~1~|...|A~m~|B~1~|B~2~|A~m+1~|...|A~n~ |=== ## mp_insert template using mp_insert = mp_append, mp_push_front, T...>>; Same as `mp_insert_c`, but with a type argument `I`. ## mp_erase_c template using mp_erase_c = mp_append, mp_drop_c>; Removes from the list `L` the elements with indices from `I` (inclusive) to `J` (exclusive). .mp_erase_c [cols="<.^4m,9*^.^1m",width=85%] |=== |*L1*|A~0~|...|A~i-1~|A~i~|...|A~j-1~|A~j~|...|A~n-1~ 10+| |*mp_erase_c*|A~0~|...|A~i-1~|A~j~|...|A~n-1~ 3+| |=== ## mp_erase template using mp_erase = mp_append, mp_drop>; Same as `mp_erase_c`, but with a type arguments `I` and `J`. ## mp_replace template using mp_replace = /*...*/; Replaces all `V` elements of `L` with `W` and returns the result. .mp_replace [cols="<.^4m,4*^.^1m",width=85%] |=== |*L1*|A~1~|V|...|A~n~ 5+| |*mp_replace*|A~1~|W|...|A~n~ |=== ## mp_replace_if template class P, class W> using mp_replace_if = /*...*/; Replaces all `T` elements of `L` for which `mp_to_bool>` is `mp_true` with `W` and returns the result. .mp_replace_if [cols="<.^4m,4*^.^1m",width=85%] |=== |*L1*|A~1~|A~2~|...|A~n~ 5+| |*P*|mp_false|mp_true|...|mp_false 5+| |*mp_replace_if*|A~1~|W|...|A~n~ |=== ## mp_replace_if_q template using mp_replace_if_q = mp_replace_if; As `mp_replace_if`, but takes a quoted metafunction. ## mp_replace_at_c template using mp_replace_at_c = /*...*/; Replaces the element of `L` at zero-based index `I` with `W` and returns the result. ## mp_replace_at template using mp_replace_at = /*...*/; Same as `mp_replace_at_c`, but with a type argument `I`. `I::value` must be a nonnegative number. ## mp_rotate_left_c template using mp_rotate_left_c = /*...*/; Moves the `N % M` initial elements of the list `L` to the back, where `M` is the size of `L`. Empty lists are unchanged. ## mp_rotate_left template using mp_rotate_left = /*...*/; Same as `mp_rotate_left_c`, but with a type argument `N`. `N::value` must be a nonnegative number. ## mp_rotate_right_c template using mp_rotate_right_c = /*...*/; Moves the `N % M` trailing elements of the list `L` to the front, where `M` is the size of `L`. Empty lists are unchanged. ## mp_rotate_right template using mp_rotate_right = /*...*/; Same as `mp_rotate_right_c`, but with a type argument `N`. `N::value` must be a nonnegative number. ## mp_copy_if template class P> using mp_copy_if = /*...*/; Copies the elements `T` of `L` for which `mp_to_bool>` is `mp_true` to a new list of the same form and returns it. ## mp_copy_if_q template using mp_copy_if_q = mp_copy_if; As `mp_copy_if`, but takes a quoted metafunction. ## mp_remove template using mp_remove = /*...*/; Removes all `V` elements of `L` and returns the result. ## mp_remove_if template class P> using mp_remove_if = /*...*/; Removes all elements `T` of `L` for which `mp_to_bool>` is `mp_true` and returns the result. ## mp_remove_if_q template using mp_remove_if_q = mp_remove_if; As `mp_remove_if`, but takes a quoted metafunction. ## mp_flatten template> using mp_flatten = /*...*/; Replaces all elements `T` of `L` that are lists of the same form as `L2` (that is, those for which `mp_similar` is `mp_true`) with their elements and returns the result. .Using mp_flatten ``` using L1 = tuple, void, tuple>; using R1 = mp_flatten; // tuple using L2 = mp_list, tuple>; using R2a = mp_flatten; // mp_list> using R2b = mp_flatten>; // mp_list, void> using L3 = mp_list, mp_list>>; using R3 = mp_flatten; // mp_list> ``` ## mp_partition template class P> using mp_partition = /*...*/; `mp_partition, P>` partitions `L` into two lists `L` and `L` such that `mp_to_bool>` is `mp_true` for the elements of `L` and `mp_false` for the elements of `L`. Returns `L, L>`. ## mp_partition_q template using mp_partition_q = mp_partition; As `mp_partition`, but takes a quoted metafunction. ## mp_sort template class P> using mp_sort = /*...*/; `mp_sort` sorts the list `L` according to the strict weak ordering `mp_to_bool>`. .Using mp_sort to sort a list of std::ratio values ---- #include using L1 = mp_list, std::ratio<1,4>>; using R1 = mp_sort; // mp_list, ratio<1,2>> ---- ## mp_sort_q template using mp_sort_q = mp_sort; As `mp_sort`, but takes a quoted metafunction. ## mp_nth_element_c template class P> using mp_nth_element_c = /*...*/; Returns the element at position `I` in `mp_sort`. ## mp_nth_element template class P> using mp_nth_element = /*...*/; Like `mp_nth_element_c`, but with a type argument `I`. `I::value` must be a nonnegative number. ## mp_nth_element_q template using mp_nth_element_q = mp_nth_element; Like `mp_nth_element`, but takes a quoted metafunction. ## mp_min_element template class P> using mp_min_element = /*...*/; `mp_min_element` returns the minimal element of the list `L` according to the ordering `mp_to_bool>`. It's equivalent to `mp_fold, mp_first, F>`, where `F` returns `mp_if, T, U>`. ## mp_min_element_q template using mp_min_element_q = mp_min_element; As `mp_min_element`, but takes a quoted metafunction. ## mp_max_element template class P> using mp_max_element = /*...*/; `mp_max_element` returns the maximal element of the list `L` according to the ordering `mp_to_bool>`. It's equivalent to `mp_fold, mp_first, F>`, where `F` returns `mp_if, T, U>`. ## mp_max_element_q template using mp_max_element_q = mp_max_element; As `mp_max_element`, but takes a quoted metafunction. ## mp_find template using mp_find = /*...*/; `mp_find` returns the index at which the type `V` is located in the list `L`. It's an alias for `mp_size_t`, where `I` is the zero-based index of the first occurrence of `V` in `L`. If `L` does not contain `V`, `mp_find` is `mp_size`. ## mp_find_if template class P> using mp_find_if = /*...*/; `mp_find_f` is an alias for `mp_size_t`, where `I` is the zero-based index of the first element `T` in `L` for which `mp_to_bool>` is `mp_true`. If there is no such element, `mp_find_if` is `mp_size`. ## mp_find_if_q template using mp_find_if_q = mp_find_if; As `mp_find_if`, but takes a quoted metafunction. ## mp_reverse template using mp_reverse = /*...*/; `mp_reverse>` is `L`. .mp_reverse [cols="<.^4m,4*^.^1m",width=85%] |=== |*L1*|A~1~|A~2~|...|A~n~ 5+| |*mp_reverse*|A~n~|A~n-1~|...|A~1~ |=== ## mp_fold template class F> using mp_fold = /*...*/; `mp_fold, V, F>` is `F< F< F< F, T2>, ...>, Tn>`, or `V`, if `L` is empty. .Using mp_fold to add the contents of a list of std::ratio values ---- #include using L1 = mp_list, std::ratio<1,4>, std::ratio<1,2>>; using R1 = mp_fold, std::ratio_add>; // std::ratio<7,8> ---- ## mp_fold_q template using mp_fold_q = mp_fold; As `mp_fold`, but takes a quoted metafunction. ## mp_reverse_fold template class F> using mp_reverse_fold = /*...*/; `mp_reverse_fold, V, F>` is `F>>>`, or `V`, if `L` is empty. ## mp_reverse_fold_q template using mp_reverse_fold_q = mp_reverse_fold; As `mp_reverse_fold`, but takes a quoted metafunction. ## mp_partial_sum template class F> using mp_partial_sum = /*...*/; `mp_partial_sum` is similar to `mp_fold`, but instead of its final result, it returns a list (of the same form as `L`) holding the intermediate results of the fold. The last element of the result of `mp_partial_sum` is the same as the result of `mp_fold`. For example, `mp_fold, V, F>` is `F, X2>, X3>`, but `mp_partial_sum, V, F>` is `mp_list, F, X2>, F, X2>, X3>>`. It's common for `F` to be `mp_plus`, in which case the result contains the partial sums of `L`. .Using mp_partial_sum ---- using L1 = mp_list_c; using R1 = mp_partial_sum, mp_plus>; // mp_list_c ---- ## mp_partial_sum_q template using mp_partial_sum_q = mp_partial_sum; As `mp_partial_sum`, but takes a quoted metafunction. ## mp_iterate template class F, template class R> using mp_iterate = /*...*/; `mp_iterate` applies `R` to `V` successively until that's no longer possible, yielding the sequence `V`, `R`, `R>`, `R>>`... It then returns an `mp_list` whose elements are formed by applying `F` to the above sequence of values. That is, it returns `mp_list, F>, F>>, ...>`. `mp_iterate` is in a way the reverse operation of `mp_reverse_fold`. Given template struct cons {}; struct nil {}; `mp_reverse_fold, nil, cons>` produces `cons>>`, which when passed as `V` to `mp_iterate` recovers the original `mp_list`. .Using mp_iterate ---- struct X1 {}; struct X2 {}; struct X3 {}; using L1 = mp_list; using R1 = mp_iterate; // L1 template struct cons {}; struct nil {}; using V2 = mp_reverse_fold; // cons>> using R2 = mp_iterate; // L1 struct Y1 {}; struct Y2 { using value_type = double; using next_type = Y1; }; struct Y3 { using value_type = float; using next_type = Y2; }; struct Y4 { using value_type = int; using next_type = Y3; }; template using value_type = typename T::value_type; template using next_type = typename T::next_type; using R3 = mp_iterate; // mp_list using R4 = mp_iterate; // mp_list ---- ## mp_iterate_q template using mp_iterate_q = mp_iterate; As `mp_iterate`, but takes quoted metafunctions. ## mp_unique template using mp_unique = /*...*/; `mp_unique` returns a list of the same form as `L` with the duplicate elements removed. ## mp_unique_if template class P> using mp_unique_if = /*...*/; As `mp_unique`, but two elements `T` and `U` are considered duplicates when `mp_to_bool>` is `mp_true`. ## mp_unique_if_q template using mp_unique_if_q = mp_unique_if; As `mp_unique_if`, but takes a quoted metafunction. ## mp_all_of template class P> using mp_all_of = mp_bool< mp_count_if::value == mp_size::value >; `mp_all_of` 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_q template using mp_all_of_q = mp_all_of; As `mp_all_of`, but takes a quoted metafunction. ## mp_none_of template class P> using mp_none_of = mp_bool< mp_count_if::value == 0 >; `mp_none_of` 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_q template using mp_none_of_q = mp_none_of; As `mp_none_of`, but takes a quoted metafunction. ## mp_any_of template class P> using mp_any_of = mp_bool< mp_count_if::value != 0 >; `mp_any_of` 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_q template using mp_any_of_q = mp_any_of; As `mp_any_of`, but takes a quoted metafunction. ## mp_for_each(f) template constexpr F mp_for_each(F&& f); `mp_for_each(f)` calls `f` with `T()` for each element `T` of the list `L`, in order. Returns `std::forward(f)`. .Using mp_for_each and a C++14 lambda to print a tuple ``` template void print( std::tuple const & tp ) { std::size_t const N = sizeof...(T); mp_for_each>( [&]( auto I ){ // I is mp_size_t<0>, mp_size_t<1>, ..., mp_size_t std::cout << std::get(tp) << std::endl; }); } ``` ## mp_with_index(i, f) template constexpr auto mp_with_index( std::size_t i, F && f ) -> decltype(std::declval()(std::declval>())); `mp_with_index(i, f)` calls `f` with `mp_size_t()` and returns the result. `i` must be less than `N`. Only `constexpr` on C++14 and higher. template constexpr auto mp_with_index( std::size_t i, F && f ) -> decltype(std::declval()(std::declval>())); Returns `mp_with_index(i, f)`. .Using mp_with_index and a C++14 lambda to print the active element of a variant ``` template void print( std::variant const& v ) { mp_with_index( v.index(), [&]( auto I ) { // I is mp_size_t{} here std::cout << std::get( v ) << std::endl; }); } ```