P3179R3
C++ parallel range algorithms

Published Proposal,

This version:
https://wg21.link/P3179R3
Authors:
(Intel)
(Intel)
(Nvidia)
Audience:
SG9, SG1, LEWG
Project:
ISO/IEC 14882 Programming Languages — C++, ISO/IEC JTC1/SC22/WG21

Abstract

This paper proposes adding parallel algorithms that work together with the C++ Ranges library.

1. Motivation

Standard parallel algorithms with execution policies which set semantic requirements to user-provided callable objects were a good start for supporting parallelism in the C++ standard.

The C++ Ranges library - ranges, views, etc. - is a powerful facility to produce lazily evaluated pipelines that can be processed by range-based algorithms. Together they provide a productive and expressive API with the room for extra optimizations.

Combining these two powerful features by adding support for execution policies to the range-based algorithms opens an opportunity to fuse several computations into one parallel algorithm call, thus reducing the overhead on parallelism. That is especially valuable for heterogeneous implementations of parallel algorithms, for which the range-based API helps reducing the number of kernels submitted to an accelerator.

Users are already using ranges and range adaptors by passing range iterators to the existing non-range parallel algorithms. [P2408R5] was adopted to enable this. This pattern is often featured when teaching C++ parallel algorithms and appears in many codebases.

iota and cartesian_product are especially common, as many compute workloads want to iterate over indices, not objects, and many work with multidimensional data. transform is also common, as it enables fusion of element-wise operations into a single parallel algorithm call, which can avoid the need for temporary storage and is more performant than two separate calls.

However, passing range iterators to non-range algorithms is unwieldy and verbose. It is surprising to users that they cannot simply pass the ranges to the parallel algorithms as they would for serial algorithms.

Scalar-Vector Multiply
Before After
std::span<double> data =;
double C =;

auto indices = std::views::iota(1, data.size());
std::for_each(std::execution::par_unseq,
  std::ranges::begin(indices),
  std::ranges::end(indices),
  [=] (auto i) { data[i] *= C; });
std::span<double> data =;
double C =;

std::ranges::for_each(std::execution::par_unseq,
  std::views::iota(1, data.size()),
  [=] (auto i) { data[i] *= C; });
Matrix Transpose
Before After
std::mdspan A{input,  N, M};
std::mdspan B{output, M, N};

auto indices = std::views::cartesian_product(
  std::views::iota(0, A.extent(0)),
  std::views::iota(0, A.extent(1)));

std::for_each(std::execution::par_unseq,
  std::ranges::begin(indices),
  std::ranges::end(indices),
  [=] (auto idx) {
    auto [i, j] = idx;
    B[j, i] = A[i, j];
  });
std::mdspan A{input,  N, M};
std::mdspan B{output, M, N};

std::ranges::for_each(std::execution::par_unseq,
  std::views::cartesian_product(
    std::views::iota(0, A.extent(0)),
    std::views::iota(0, A.extent(1))),
  [=] (auto idx) {
    auto [i, j] = idx;
    B[j, i] = A[i, j];
  });

Earlier, [P2500R2] proposed to add the range-based C++ parallel algorithms together with its primary goal of extending algorithms with schedulers. We have decided to split those parts to separate papers, which could progress independently.

2. Design overview

This paper proposes execution policy support for C++ range-based algorithms. In the nutshell, the proposal extends C++ range algorithms with overloads taking any standard C++ execution policy as a function parameter. These overloads are further referred to as parallel range algorithms.

The proposal is targeted to C++26.

2.1. Design summary

2.1.1. Differences to serial range algorithms

Comparing to the C++20 serial range algorithms, we propose the following modifications:

2.1.2. Differences to C++17 parallel algorithms

In addition to data sequences being passed as either ranges or "iterator and sentinel" pairs, the following differences to the C++17 parallel algorithms are proposed:

2.1.3. Other design aspects

2.2. Coexistence with schedulers

We believe that adding parallel range algorithms does not have the risk of conflict with anticipated scheduler-based algorithms, because an execution policy does not satisfy the requirements for a policy-aware scheduler ([P2500R2]), a sender ([P3300R0]), or really anything else from [P2300R9] that can be used to specify such algorithms.

At this point we do not, however, discuss how the appearance of schedulers may or should impact the execution rules for parallel algorithms specified in [algorithms.parallel.exec], and just assume that the same rules apply to the range algorithms with execution policies.

2.3. Algorithm return types

We explored possible algorithm return types and came to conclusion that returning the same type as serial range algorithms is the preferred option to make the changes for enabling parallelism minimal.

auto res = std::ranges::sort(v);

becomes:

auto res = std::ranges::sort(std::execution::par, v);

However, std::ranges::for_each and std::ranges::for_each_n require special consideration because previous design decisions suggest that there should be a difference between serial and parallel versions.

The following table summarizes return value types for the existing variants of these two algorithms:

API Return type
std::for_each Function
Parallel std::for_each void
std::for_each_n Iterator
Parallel std::for_each_n Iterator
std::ranges::for_each for_each_result<ranges::borrowed_iterator_t<Range>, Function>
std::ranges::for_each, I + S overload for_each_result<Iterator, Function>
std::ranges::for_each_n for_each_n_result<Iterator, Function>

While the serial std::for_each returns the obtained function object with all modifications it might have accumulated, the return type for the parallel std::for_each is void because, as stated in the standard, "parallelization often does not permit efficient state accumulation". For efficient parallelism an implementation can make multiple copies of the function object, which for that purpose is allowed to be copyable and not just movable like for the serial for_each. That implies that users cannot rely on any state accumulation within that function object, so it does not make sense (and might be even dangerous) to return it.

In std::ranges, the return type of for_each and for_each_n is unified to return both an iterator and the function object.

Based on the analysis above and the feedback from SG9 we think that the most reasonable return type for parallel variants of std::ranges::for_each and std::ranges::for_each_n should be:

API Return type
Parallel std::ranges::for_each ranges::borrowed_iterator_t<Range>
Parallel std::ranges::for_each, I + S overload Iterator
Parallel std::ranges::for_each_n Iterator

2.4. Non ADL-discoverable functions

We believe the proposed functionality should have the same behavior as serial range algorithms regarding the name lookup. For now, the new overloads are supposed to be special functions that are not discoverable by ADL (the status quo of the standard for serial range algorithms).

[P3136R0] suggests to respecify range algorithms to be actual function objects. If adopted, that proposal will apply to all algorithms in the std::ranges namespace, thus automatically covering the parallel algorithms we propose.

Either way, adding parallel versions of the range algorithms should not be a problem. Please see § 4.1 Possible implementation of a parallel range algorithm for more information.

2.5. Requiring random_access_iterator or random_access_range

C++17 parallel algorithms minimally require LegacyForwardIterator for data sequences, but in our opinion, it is not quite suitable for an efficient parallel implementation. Therefore for parallel range algorithms we propose to require random access ranges and iterators.

Using parallel algorithms with forward ranges will in most cases give little to no benefit, and may even reduce performance due to extra overheads. We believe that forward ranges and iterators are bad abstractions for parallel data processing, and allowing those could result in wrong expectations and unsatisfactory user experience with parallel algorithms.

Many parallel programming models that are well known and widely used in the industry, including OpenMP, OpenCL, CUDA, SYCL, oneTBB, define iteration or data spaces for their parallel constructs in ways that allow creating sufficient parallel work quickly and efficiently. A key property for this is the ability to split the work into smaller chunks. These programming models allow to control the amount of work per chunk and sometimes the ways chunks are created and/or scheduled. All these also support iteration spaces up to at least 3 dimensions.

Except for tbb::parallel_for_each in oneTBB which can work with forward iterators, these parallel programming models require random access iterators or some equivalent, such as numeric indexes or pointers. This is natural, as referring to an arbitrary point in the iteration space at constant time is the main and by far simplest way to create parallel work. Forward iterators, on the other hand, are notoriously bad for splitting a sequence that can only be done in linear time. Moreover, if the output of an algorithm should preserve the order of its input, which is typical for the C++ algorithms, it requires additional synchronization or/and additional space with forward iterators and comes almost for granted with random access ones.

These very programming models are often used as backends to implement the C++ standard parallelism. Not surprisingly, most implementations fall back to serial processing if data sequences have no random access. Of the GNU libstdc++, LLVM libc++, and MSVC’s standard library, only the latter attempts to process forward iterator based sequences in parallel, for which it first needs to serially iterate over a whole sequence once or even twice. oneAPI DPC++ library (oneDPL) supports forward iterators only for a very few algorithms, only for par and only in the implementation based on oneTBB.

According to the SG1/SG9 feedback we have got earlier, there seemingly are two main reasons why others do not want to restrict parallel algorithms by only random access ranges:

Given the other aspects of the proposed design, we believe some degree of inconsistency with C++17 parallel algorithms is inevitable and should not become a gating factor for important design decisions.

The question of supporting the standard views that do not provide random access is very important. We think though that it should better be addressed through proper abstractions and new concepts defining iteration spaces, including multidimensional ones, suitable for parallel algorithms. We intend to work on developing these (likely in another paper), however it requires time and effort to make it right, and we think trying to squeeze that into C++26 adds significant risks. For now, random access ranges with known bounds (see § 2.7 Requiring ranges to be bounded) is probably the best approximation that exists in the standard. Starting from that and gradually enabling other types of iteration spaces in a source-compatible manner seems to us better than blanket allowance of any forward_range.

2.6. Taking range as an output

In the previous revision we proposed a range as the output for the overloads that take ranges for input. Similarly, we proposed a sentinel for output where input is passed as "iterator and sentinel".

This topic was discussed on the joint SG1 and SG9 session (St. Louis, 2024) and the feedback was that the extra discussion is required and the semantics of some algorithms is not clear with the range-as-an-output. Thus, it requires deeper investigation.

We do not push for this design aspect as a part of this proposal. Instead, we are going to write a separate paper to cover this topic.

See [P3179R2] for more details.

2.7. Requiring ranges to be bounded

One of the requirements we want to put on the parallel range algorithms is to disallow unbounded input and, ideally, output. The reasons for that are:

In the case of two or more input ranges or sequences, for some algorithms it can be sufficient for just one to be bounded. The other input ranges are then assumed to have at least as many elements as the bounded one. This enables unbounded ranges such as views::repeat in certain useful patterns, for example:

void normalize_parallel(range auto&& v) {
  auto mx = reduce(execution::par, v, ranges::max{});
  transform(execution::par, v, views::repeat(mx), v.begin(), divides);
}

If several provided ranges or sequences are bounded, an algorithm should stop as soon as the end is reached for the shortest one. There are already precedents in the standard that an algorithm takes two sequences with potentially different input sizes and chooses the smaller size as the number of iterations it is going to make, such as std::ranges::transform and std::ranges::mismatch. For the record, std::transform (including the overload with execution policy) doesn’t support different input sizes, while std::mismatch does.

2.8. Requirements for callable parameters

In [P3179R0] we proposed that parallel range algorithms should require function objects for predicates, comparators, etc. to have const-qualified operator(), with the intent to provide compile-time diagnostics for mutable function objects which might be unsafe for parallel execution. We have got contradictory feedback from SG1 and SG9 on that topic: SG1 preferred to keep the behavior consistent with C++17 parallel algorithms, while SG9 supported our design intent.

We did extra investigation and decided that requiring const-qualified operator at compile-time is not strictly necessary because:

The following example works fine for serial code. While it compiles for parallel code, users should not assume that the semantics remains intact. Since the parallel version of for_each requires function object to be copyable, it is not guaranteed that all for_each iterations are processed by the same function object. Practically speaking, users cannot rely on accumulating any state modifications in a parallel for_each call.

struct callable
{
    void operator()(int& x)
    {
        ++x;
        ++i; // a data race if the callable is executed concurrently
    }
    int get_i() const {
        return i;
    }
private:
    int i = 0;
};

callable c;

// serial for_each call
auto fun = std::for_each(v.begin(), v.end(), c);

// parallel for_each call
// The callable object cannot be read because parallel for_each version purposefully returns void
std::for_each(std::execution::par, v.begin(), v.end(), c);

// for_each serial range version call
auto [_, fun] = std::ranges::for_each(v.begin(), v.end(), c);

We allow the same callable to be used in the proposed std::ranges::for_each.

// callable is used from the previous code snippet
callable c;
// The returned iterator is ignored
std::ranges::for_each(std::execution::par, v.begin(), v.end(), c);

Again, even though c accumulates state modifications, one cannot rely on that because an algorithm implementation is allowed to make as many copies of c as it wants. Of course, this can be overcome by using std::reference_wrapper but that might lead to data races.

// callable is used from the previous code snippet
// Wrapping a callable object with std::reference_wrapper compiles, but might result in data races
callable c;
std::ranges::for_each(std::execution::par, v.begin(), v.end(), std::ref(c));

Our conclusion is that it’s user responsibility to provide such a callable that avoids data races, same as for C++17 parallel algorithms.

2.9. Parallel range algorithms are not customization points

We do not propose the parallel range algorithms to be customization points because it’s unclear which parameter to customize for. One could argue that customizations may exist for execution policies, but we expect custom execution policies to become unnecessary once the C++ algorithms will work with schedulers/senders/receivers.

2.10. constexpr parallel range algorithms

[P2902R0] suggests allowing algorithms with execution policies to be used in constant expressions. We do not consider that as a primary design goal for our work, however we will happily align with that proposal in the future once it progresses towards adoption into the working draft.

3. More examples

3.1. Change existing code to use parallel range algorithms

One of the goals is to require a minimal amount of changes when switching from the existing API to parallel range algorithms. However, that simplicity should not create hidden issues negatively impacting the overall user experience. We believe that the proposal provides a good balance in that regard.

As an example, let’s look at using for_each to apply a lambda function to all elements of a std::vector v.

For the serial range-based for_each call:

std::ranges::for_each(v, [](auto& x) { ++x; });

switching to the parallel version will look like:

std::ranges::for_each(std::execution::par, v, [](auto& x) { ++x; });

In this simple case, the only change is an execution policy added as the first function argument. It will also hold for the "iterator and sentinel" overload of std::ranges::for_each.

The C++17 parallel for_each call:

std::for_each(std::execution::par, v.begin(), v.end(), [](auto& x) { ++x; });

can be changed to one of the following:

// Using iterator and sentinel
std::ranges::for_each(std::execution::par, v.begin(), v.end(), [](auto& x) { ++x; });

// Using vector as a range
std::ranges::for_each(std::execution::par, v, [](auto& x) { ++x; });

So, here only changing the namespace is necessary, though users might also change v.begin(), v.end() to just v.

However, for other algorithms more changes might be necessary.

3.2. Less parallel algorithm calls and better expressiveness

Let’s consider the following example:

reverse(policy, begin(data), end(data));
transform(policy, begin(data), end(data), begin(result), [](auto i){ return i * i; });
auto res = any_of(policy, begin(result), end(result), pred);

It has three stages and eventually tries to answer the question if the input sequence contains an element after reversing and transforming it. The interesting considerations are:

Let’s make it better:

// With fancy iterators
auto res = any_of(policy,
                  make_transform_iterator(make_reverse_iterator(end(data)),
                                          [](auto i){ return i * i; }),
                  make_transform_iterator(make_reverse_iterator(begin(data)),
                                          [](auto i){ return i * i; }),
                  pred);

Now there is only one parallel algorithm call, and any_of can skip unneeded work. However, this variation also has interesting considerations:

Let’s improve the example further with the proposed API:

// With ranges
auto res = any_of(policy, data | views::reverse | views::transform([](auto i){ return i * i; }),
                  pred);

The example above lacks the drawbacks described for the previous variations:

4. Proposed API

Note: std::ranges::for_each and std::ranges::transform are used as reference points. When the design is ratified, it will be spread across other algorithms.

// for_each
template <class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S,
          class Proj = identity, indirectly_unary_invocable<projected<I, Proj>> Fun>
  I
    for_each(ExecutionPolicy&& policy, I first, S last, Fun f, Proj proj = {});

template <class ExecutionPolicy, ranges::random_access_range R, class Proj = identity,
         indirectly_unary_invocable<projected<ranges::iterator_t<R>, Proj>> Fun>
requires ranges::sized_range<R>
  ranges::borrowed_iterator_t<R>
    for_each(ExecutionPolicy&& policy, R&& r, Fun f, Proj proj = {});

// binary transform with an output range and an output sentinel
template< typename ExecutionPolicy,
          random_access_iterator I1, sentinel_for<I1> S1,
          random_access_iterator I2, sentinel_for<I2> S2,
          random_access_iterator O,
          copy_constructible F,
          class Proj1 = identity, class Proj2 = identity >
  requires indirectly_writable<O,
             indirect_result_t<F&, projected<I1, Proj1>, projected<I2, Proj2>>>
         && (sized_sentinel_for<S1, I1> || sized_sentinel_for<S2, I2>)
  ranges::binary_transform_result<I1, I2, O>
    transform( ExecutionPolicy&& policy, I1 first1, S1 last1, I2 first2, S2 last2, O result,
               F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {} );

template< typename ExecutionPolicy,
          ranges::random_access_range R1,
          ranges::random_access_range R2,
          random_access_iterator O,
          copy_constructible F,
          class Proj1 = identity, class Proj2 = identity >
requires indirectly_writable<O,
             indirect_result_t<F&,
                 projected<ranges::iterator_t<R1>, Proj1>,
                 projected<ranges::iterator_t<R2>, Proj2>>>
         && (ranges::sized_range<R1>
             || ranges::sized_range<R2>)
ranges::binary_transform_result<ranges::borrowed_iterator_t<R1>,
                                  ranges::borrowed_iterator_t<R2>,
                                  O>
    transform( ExecutionPolicy&& policy, R1&& r1, R2&& r2, O result, F binary_op,
               Proj1 proj1 = {}, Proj2 proj2 = {} );

4.1. Possible implementation of a parallel range algorithm

// A possible implementation of std::ranges::for_each
namespace ranges
{
namespace __detail
{
struct __for_each_fn
{
    // ...
    // Existing serial overloads
    // ...

    // The overload for unsequenced and parallel policies. Requires random_access_iterator
    template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S,
             class Proj = identity, indirectly_unary_invocable<projected<I, Proj>> Fun>
                 requires is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>>
    I
    operator()(ExecutionPolicy&& exec, I first, S last, Fun f, Proj proj = {}) const
    {
        // properly handle the execution policy;
        // for the reference, a serial implementation is provided
        for (; first != last; ++first)
        {
            std::invoke(f, std::invoke(proj, *first));
        }
        return first;
    }

    template<class ExecutionPolicy, random_access_range R, class Proj = identity,
             indirectly_unary_invocable<projected<iterator_t<R>, Proj>> Fun>
    ranges::borrowed_iterator_t<R>
    operator()(ExecutionPolicy&& exec, R&& r, Fun f, Proj proj = {}) const
    {
        return (*this)(std::forward<ExecutionPolicy>(exec), std::ranges::begin(r),
                       std::ranges::end(r), f, proj);
    }
}; // struct for_each
} // namespace __detail
inline namespace __for_each_fn_namespace
{
inline constexpr __detail::__for_each_fn for_each;
} // __for_each_fn_namespace
} // namespace ranges

5. Absence of some serial range-based algorithms

We understand that some useful algorithms do not yet exist in std::ranges, for example, most of generalized numeric operations [numeric.ops]. The goal of this paper is however limited to adding overloads with ExecutionPolicy to the existing algorithms in std::ranges namespace. Any follow-up paper that adds <numeric> algorithms to std::ranges should also consider adding dedicated overloads with ExecutionPolicy.

6. Further exploration

6.1. Thread-safe views examination

We need to understand better whether using some views with parallel algorithms might result in data races. While some investigation was done by other authors in [P3159R0], it’s mostly not about the data races but about ability to parallelize processing of data represented by various views.

We need to invest more time to understand the implications of sharing a state between view and iterator on the possibility of data races. One example is transform_view, where iterators keep pointers to the function object that is stored in the view itself.

Here are questions we want to answer (potentially not a complete list):

7. Formal wording

7.1. Modify [algorithms.parallel.defns]

Parallel algorithms access objects indirectly accessible via their arguments by invoking the following functions:

7.2. Modify [algorithms.parallel.user]

Unless otherwise specified, function invocable objects passed into parallel algorithms as objects of type Predicate, BinaryPredicate, Compare, UnaryOperation, BinaryOperation, BinaryOperation1, BinaryOperation2, BinaryDivideOp, Proj and the operators used by the analogous overloads to these parallel algorithms that are formed by an invocation with the specified default predicate or operation (where applicable) shall not directly or indirectly modify objects via their arguments, nor shall they rely on the identity of the provided objects.

7.3. Modify all_of in [alg.all.of]

template<input_iterator I, sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  constexpr bool ranges::all_of(I first, S last, Pred pred, Proj proj = {});
template<input_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  constexpr bool ranges::all_of(R&& r, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  constexpr bool ranges::all_of(ExecutionPolicy&& exec, I first, S last, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires ranges::sized_range<R>
  constexpr bool ranges::all_of(ExecutionPolicy&& exec, R&& r, Pred pred, Proj proj = {});

7.4. Modify any_of in [alg.any.of]

template<input_iterator I, sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  constexpr bool ranges::any_of(I first, S last, Pred pred, Proj proj = {});
template<input_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  constexpr bool ranges::any_of(R&& r, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  bool ranges::any_of(ExecutionPolicy&& exec, I first, S last, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires ranges::sized_range<R>
  bool ranges::any_of(ExecutionPolicy&& exec, R&& r, Pred pred, Proj proj = {});

7.5. Modify none_of in [alg.none.of]

template<input_iterator I, sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  constexpr bool ranges::none_of(I first, S last, Pred pred, Proj proj = {});
template<input_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  constexpr bool ranges::none_of(R&& r, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  bool ranges::none_of(ExecutionPolicy&& exec, I first, S last, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires ranges::sized_range<R>
  bool ranges::none_of(ExecutionPolicy&& exec, R&& r, Pred pred, Proj proj = {});

7.6. Modify contains in [alg.contains]

template<input_iterator I, sentinel_for<I> S, class Proj = identity,
         class T = projected_value_t<I, Proj>>
  requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
  constexpr bool ranges::contains(I first, S last, const T& value, Proj proj = {});
template<input_range R, class Proj = identity, class T = projected_value_t<iterator_t<R>, Proj>>
  requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T*>
  constexpr bool ranges::contains(R&& r, const T& value, Proj proj = {});

Returns: ranges::find(std::move(first), last, value, proj) != last.

template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         class T = projected_value_t<I, Proj>>
  requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
  bool ranges::contains(ExecutionPolicy&& exec, I first, S last, const T& value, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity, class T = projected_value_t<iterator_t<R>, Proj>>
  requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T*> &&
    ranges::sized_range<R>
  bool ranges::contains(ExecutionPolicy&& exec, R&& r, const T& value, Proj proj = {});

Returns: ranges::find(std::forward<ExecutionPolicy>(exec), std::move(first), last, value, proj) != last.

template<forward_iterator I1, sentinel_for<I1> S1,
         forward_iterator I2, sentinel_for<I2> S2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
  constexpr bool ranges::contains_subrange(I1 first1, S1 last1, I2 first2, S2 last2,
                                           Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<forward_range R1, forward_range R2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
  constexpr bool ranges::contains_subrange(R1&& r1, R2&& r2, Pred pred = {},
                                           Proj1 proj1 = {}, Proj2 proj2 = {});

Returns: first2 == last2 || !ranges::search(first1, last1, first2, last2, pred, proj1, proj2).empty().

template<class ExecutionPolicy, random_access_iterator I1, sized_sentinel_for<I1> S1,
         random_access_iterator I2, sized_sentinel_for<I2> S2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
  bool ranges::contains_subrange(ExecutionPolicy&& exec, I1 first1, S1 last1, I2 first2, S2 last2,
                                 Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_range R1, random_access_range R2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2> &&
    ranges::sized_range<R1> && ranges::sized_range<R2>
  bool ranges::contains_subrange(ExecutionPolicy&& exec, R1&& r1, R2&& r2, Pred pred = {},
                                 Proj1 proj1 = {}, Proj2 proj2 = {});

Returns: first2 == last2 || !ranges::search(std::forward<ExecutionPolicy>(exec), first1, last1, first2, last2, pred, proj1, proj2).empty().

7.7. Modify for_each in [alg.foreach]

template<input_iterator I, sentinel_for<I> S, class Proj = identity,
         indirectly_unary_invocable<projected<I, Proj>> Fun>
  constexpr ranges::for_each_result<I, Fun>
    ranges::for_each(I first, S last, Fun f, Proj proj = {});
template<input_range R, class Proj = identity,
         indirectly_unary_invocable<projected<iterator_t<R>, Proj>> Fun>
  constexpr ranges::for_each_result<borrowed_iterator_t<R>, Fun>
    ranges::for_each(R&& r, Fun f, Proj proj = {});

Effects: Calls invoke(f, invoke(proj, *i)) for every iterator i in the range [first, last), starting from first and proceeding to last - 1.

[Note x: If the result of invoke(proj, *i) is a mutable reference, f can apply non-constant functions. — end note]

Returns: {last, std::move(f)}.

Complexity: Applies f and proj exactly last - first times.

Remarks: If f returns a result, the result is ignored.

[Note x: The overloads in namespace ranges require Fun to model copy_constructible. — end note]

template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         indirectly_unary_invocable<projected<I, Proj>> Fun>
  I ranges::for_each(ExecutionPolicy&& exec, I first, S last, Fun f, Proj proj = {});

template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirectly_unary_invocable<projected<iterator_t<R>, Proj>> Fun>
    requires sized_range<R>
  borrowed_iterator_t<R>
    ranges::for_each(ExecutionPolicy&& exec, R&& r, Fun f, Proj proj = {});

Effects: Calls invoke(f, invoke(proj, *i)) for every iterator i in the range [first, last).

[Note x: If the result of invoke(proj, *i) is a mutable reference, f can apply non-constant functions. — end note]

Returns: last.

Complexity: Applies f and proj exactly last - first times.

Remarks: If f returns a result, the result is ignored. Implementations do not have the freedom granted under [algorithms.parallel.exec] to make arbitrary copies of elements from the input sequence.

[Note x: The overloads in namespace ranges require Fun to model copy_constructible. — end note]

[Note x: Do not return a copy of its Fun parameter, since parallelization often does not permit efficient state accumulation. — end note]

template<input_iterator I, class Proj = identity,
         indirectly_unary_invocable<projected<I, Proj>> Fun>
  constexpr ranges::for_each_n_result<I, Fun>
    ranges::for_each_n(I first, iter_difference_t<I> n, Fun f, Proj proj = {});

Preconditions: n >= 0 is true.

Effects: Calls invoke(f, invoke(proj, *i)) for every iterator i in the range [first, first + n) in order.

[Note x: If the result of invoke(proj, *i) is a mutable reference, f can apply non-constant functions. — end note]

Returns: {first + n, std::move(f)}.

Remarks: If f returns a result, the result is ignored.

[Note x: The overload in namespace ranges requires Fun to model copy_constructible. — end note]

template<class ExecutionPolicy, random_access_iterator I, class Proj = identity,
         indirectly_unary_invocable<projected<I, Proj>> Fun>
  I ranges::for_each_n(ExecutionPolicy&& exec, I first, iter_difference_t<I> n,
                       Fun f, Proj proj = {});

Preconditions: n >= 0 is true.

Effects: Calls invoke(f, invoke(proj, *i)) for every iterator i in the range [first, first + n).

[Note x: If the result of invoke(proj, *i) is a mutable reference, f can apply non-constant functions. — end note]

Returns: first + n.

Remarks: If f returns a result, the result is ignored.

[Note x: The overload in namespace ranges requires Fun to model copy_constructible. — end note]

[Note x: Does not return a copy of its Fun parameter, since parallelization often does not permit efficient state accumulation. — end note]

7.8. Modify find in [alg.find]

template<input_iterator I, sentinel_for<I> S, class Proj = identity,
         class T = projected_value_t<I, Proj>>
  requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
  constexpr I ranges::find(I first, S last, const T& value, Proj proj = {});
template<input_range R, class Proj = identity, class T = projected_value_t<iterator_t<R>, Proj>>
  requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T*>
  constexpr borrowed_iterator_t<R>
    ranges::find(R&& r, const T& value, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         class T = projected_value_t<I, Proj>>
  requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
  I ranges::find(ExecutionPolicy&& exec, I first, S last, const T& value, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity, class T = projected_value_t<iterator_t<R>, Proj>>
  requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T*> && sized_range<R>
  borrowed_iterator_t<R> ranges::find(ExecutionPolicy&& exec, R&& r, const T& value, Proj proj = {});
template<input_iterator I, sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  constexpr I ranges::find_if(I first, S last, Pred pred, Proj proj = {});
template<input_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  constexpr borrowed_iterator_t<R>
    ranges::find_if(R&& r, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  I ranges::find_if(ExecutionPolicy&& exec, I first, S last, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires sized_range<R>
  borrowed_iterator_t<R> ranges::find_if(ExecutionPolicy&& exec, R&& r, Pred pred, Proj proj = {});
template<input_iterator I, sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  constexpr I ranges::find_if_not(I first, S last, Pred pred, Proj proj = {});
template<input_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  constexpr borrowed_iterator_t<R>
    ranges::find_if_not(R&& r, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  I ranges::find_if_not(ExecutionPolicy&& exec, I first, S last, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires sized_range<R>
  borrowed_iterator_t<R> ranges::find_if_not(ExecutionPolicy&& exec, R&& r, Pred pred, Proj proj = {});

7.9. Modify find_last in [alg.find.last]

template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
         class T = projected_value_t<I, Proj>>
  requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
  constexpr subrange<I> ranges::find_last(I first, S last, const T& value, Proj proj = {});
template<forward_range R, class Proj = identity,
         class T = projected_value_t<iterator_t<R>, Proj>>
  requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T*>
  constexpr borrowed_subrange_t<R> ranges::find_last(R&& r, const T& value, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         class T = projected_value_t<I, Proj>>
  requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
  subrange<I> ranges::find_last(ExecutionPolicy&& exec, I first, S last, const T& value, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity, class T = projected_value_t<iterator_t<R>, Proj>>
  requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T*> && sized_range<R>
  borrowed_subrange_t<R> ranges::find_last(ExecutionPolicy&& exec, R&& r, const T& value, Proj proj = {});
template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  constexpr subrange<I> ranges::find_last_if(I first, S last, Pred pred, Proj proj = {});
template<forward_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  constexpr borrowed_subrange_t<R> ranges::find_last_if(R&& r, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  subrange<I> ranges::find_last_if(ExecutionPolicy&& exec, I first, S last, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires sized_range<R>
  borrowed_subrange_t<R> ranges::find_last_if(ExecutionPolicy&& exec, R&& r, Pred pred, Proj proj = {});
template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  constexpr subrange<I> ranges::find_last_if_not(I first, S last, Pred pred, Proj proj = {});
template<forward_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  constexpr borrowed_subrange_t<R> ranges::find_last_if_not(R&& r, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  subrange<I> ranges::find_last_if_not(ExecutionPolicy&& exec, I first, S last, Pred pred, Proj proj = {});

template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires sized_range<R>
  borrowed_subrange_t<R> ranges::find_last_if_not(ExecutionPolicy&& exec, R&& r, Pred pred, Proj proj = {});

7.10. Modify find_end in [alg.find.end]

template<forward_iterator I1, sentinel_for<I1> S1, forward_iterator I2, sentinel_for<I2> S2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
  constexpr subrange<I1>
    ranges::find_end(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
                     Proj1 proj1 = {}, Proj2 proj2 = {});
template<forward_range R1, forward_range R2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
  constexpr borrowed_subrange_t<R1>
    ranges::find_end(R1&& r1, R2&& r2, Pred pred = {},
                     Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_iterator I1, sized_sentinel_for<I1> S1, random_access_iterator I2,
         sized_sentinel_for<I2> S2, class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
  subrange<I1> ranges::find_end(ExecutionPolicy&& exec, I1 first1, S1 last1, I2 first2, S2 last2,
                                Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {});

template<class ExecutionPolicy, random_access_range R1, random_access_range R2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
             && sized_range<R1> && sized_range<R2>
  borrowed_subrange_t<R1> ranges::find_end(ExecutionPolicy&& exec, R1&& r1, R2&& r2,
                                           Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {});

7.11. Modify find_first_of in [alg.find.first.of]

template<input_iterator I1, sentinel_for<I1> S1, forward_iterator I2, sentinel_for<I2> S2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
  constexpr I1 ranges::find_first_of(I1 first1, S1 last1, I2 first2, S2 last2,
                                     Pred pred = {},
                                     Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, forward_range R2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
  constexpr borrowed_iterator_t<R1>
    ranges::find_first_of(R1&& r1, R2&& r2,
                          Pred pred = {},
                          Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_iterator I1, sized_sentinel_for<I1> S1,
         random_access_iterator I2, sized_sentinel_for<I2> S2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
  I1 ranges::find_first_of(ExecutionPolicy&& exec, I1 first1, S1 last1, I2 first2, S2 last2,
                           Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {});

template<class ExecutionPolicy, random_access_range R1, random_access_range R2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
             && sized_range<R1> && sized_range<R2>
  borrowed_iterator_t<R1> ranges::find_first_of(ExecutionPolicy&& exec, R1&& r1, R2&& r2,
                                                Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {});

7.12. Modify adjacent_find in [alg.adjacent.find]

template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
         indirect_binary_predicate<projected<I, Proj>,
                                   projected<I, Proj>> Pred = ranges::equal_to>
  constexpr I ranges::adjacent_find(I first, S last, Pred pred = {}, Proj proj = {});
template<forward_range R, class Proj = identity,
         indirect_binary_predicate<projected<iterator_t<R>, Proj>,
                                   projected<iterator_t<R>, Proj>> Pred = ranges::equal_to>
  constexpr borrowed_iterator_t<R> ranges::adjacent_find(R&& r, Pred pred = {}, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         indirect_binary_predicate<projected<I, Proj>, projected<I, Proj>> Pred = ranges::equal_to>
  I ranges::adjacent_find(ExecutionPolicy&& exec, I first, S last, Pred pred = {}, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_binary_predicate<projected<iterator_t<R>, Proj>, projected<iterator_t<R>, Proj>> Pred
           = ranges::equal_to>
  requires sized_range<R>
  borrowed_iterator_t<R> ranges::adjacent_find(ExecutionPolicy&& exec, R&& r, Pred pred = {}, Proj proj = {});

7.13. Modify count in [alg.count]

template<input_iterator I, sentinel_for<I> S, class Proj = identity,
         class T = projected_value_t<I, Proj>>
  requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
  constexpr iter_difference_t<I>
    ranges::count(I first, S last, const T& value, Proj proj = {});
template<input_range R, class Proj = identity, class T = projected_value_t<iterator_t<R>, Proj>>
  requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T*>
  constexpr range_difference_t<R>
    ranges::count(R&& r, const T& value, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         class T = projected_value_t<I, Proj>>
  requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
  iter_difference_t<I> ranges::count(ExecutionPolicy&& exec, I first, S last, const T& value, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity, class T = projected_value_t<iterator_t<R>, Proj>>
  requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T*> && sized_range<R>
  range_difference_t<R> ranges::count(ExecutionPolicy&& exec, R&& r, const T& value, Proj proj = {});
template<input_iterator I, sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  constexpr iter_difference_t<I>
    ranges::count_if(I first, S last, Pred pred, Proj proj = {});
template<input_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  constexpr range_difference_t<R>
    ranges::count_if(R&& r, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  iter_difference_t<I> ranges::count_if(ExecutionPolicy&& exec, I first, S last, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires sized_range<R>
  range_difference_t<R> ranges::count_if(ExecutionPolicy&& exec, R&& r, Pred pred, Proj proj = {});

7.14. Modify mismatch in [alg.mismatch]

template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
  constexpr ranges::mismatch_result<I1, I2>
    ranges::mismatch(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
                     Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, input_range R2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
  constexpr ranges::mismatch_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>>
    ranges::mismatch(R1&& r1, R2&& r2, Pred pred = {},
                     Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_iterator I1, sentinel_for<I1> S1, random_access_iterator I2, sentinel_for<I2> S2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2> && (sized_sentinel_for<S1, I1> || sized_sentinel_for<S2, I2>)
  ranges::mismatch_result<I1, I2>
    ranges::mismatch(ExecutionPolicy&& exec, I1 first1, S1 last1, I2 first2,S2 last2,
                     Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_range R1, random_access_range R2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2> && (sized_range<R1> || sized_range<R2>)
  ranges::mismatch_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>>
    ranges::mismatch(ExecutionPolicy&& exec, R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {});

7.15. Modify equal in [alg.equal]

template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
  constexpr bool ranges::equal(I1 first1, S1 last1, I2 first2, S2 last2,
                               Pred pred = {},
                               Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, input_range R2, class Pred = ranges::equal_to,
         class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
  constexpr bool ranges::equal(R1&& r1, R2&& r2, Pred pred = {},
                               Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_iterator I1, sentinel_for<I1> S1,
         random_access_iterator I2, sentinel_for<I2> S2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2> &&
    (sized_sentinel_for<S1, I1> || sized_sentinel_for<S2, I2>)
  bool ranges::equal(ExecutionPolicy&& exec, I1 first1, S1 last1, I2 first2, S2 last2,
                     Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_range R1, random_access_range R2, class Pred = ranges::equal_to,
         class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2> &&
    (sized_range<R1> || sized_range<R2>)
  bool ranges::equal(ExecutionPolicy&& exec, R1&& r1, R2&& r2,
                     Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<forward_iterator I1, sentinel_for<I1> S1, forward_iterator I2,
         sentinel_for<I2> S2, class Pred = ranges::equal_to,
         class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
  constexpr subrange<I1>
    ranges::search(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
                   Proj1 proj1 = {}, Proj2 proj2 = {});
template<forward_range R1, forward_range R2, class Pred = ranges::equal_to,
         class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
  constexpr borrowed_subrange_t<R1>
    ranges::search(R1&& r1, R2&& r2, Pred pred = {},
                   Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_iterator I1, sized_sentinel_for<I1> S1,
         random_access_iterator I2, sized_sentinel_for<I2> S2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
    subrange<I1>
      ranges::search(ExecutionPolicy&& exec, I1 first1, S1 last1, I2 first2, S2 last2,
                     Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {});

template<class ExecutionPolicy, random_access_range R1, random_access_range R2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
           && sized_range<R1> && sized_range<R2>
    borrowed_subrange_t<R1>
      ranges::search(ExecutionPolicy&& exec, R1&& r1, R2&& r2,
                     Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<forward_iterator I, sentinel_for<I> S,
         class Pred = ranges::equal_to, class Proj = identity,
         class T = projected_value_t<I, Proj>>
  requires indirectly_comparable<I, const T*, Pred, Proj>
  constexpr subrange<I>
    ranges::search_n(I first, S last, iter_difference_t<I> count,
                     const T& value, Pred pred = {}, Proj proj = {});
template<forward_range R, class Pred = ranges::equal_to,
         class Proj = identity, class T = projected_value_t<iterator_t<R>, Proj>>
  requires indirectly_comparable<iterator_t<R>, const T*, Pred, Proj>
  constexpr borrowed_subrange_t<R>
    ranges::search_n(R&& r, range_difference_t<R> count,
                     const T& value, Pred pred = {}, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S,
         class Pred = ranges::equal_to, class Proj = identity,
         class T = projected_value_t<I, Proj>>
  requires indirectly_comparable<I, const T*, Pred, Proj>
    subrange<I>
      ranges::search_n(ExecutionPolicy&& exec, I first, S last, iter_difference_t<I> count,
                       const T& value, Pred pred = {}, Proj proj = {});

template<class ExecutionPolicy, random_access_range R, class Pred = ranges::equal_to,
         class Proj = identity, class T = projected_value_t<iterator_t<R>, Proj>>
  requires indirectly_comparable<iterator_t<R>, const T*, Pred, Proj>
           && sized_range<R>
    borrowed_subrange_t<R>
      ranges::search_n(ExecutionPolicy&& exec, R&& r, range_difference_t<R> count,
                       const T& value, Pred pred = {}, Proj proj = {});

7.17. Modify starts_with in [alg.starts.with]

template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
  constexpr bool ranges::starts_with(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
                                     Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, input_range R2, class Pred = ranges::equal_to, class Proj1 = identity,
         class Proj2 = identity>
  requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
  constexpr bool ranges::starts_with(R1&& r1, R2&& r2, Pred pred = {},
                                     Proj1 proj1 = {}, Proj2 proj2 = {});

Returns: ranges::mismatch(std::move(first1), last1, std::move(first2), last2, pred, proj1, proj2).in2 == last2

template<class ExecutionPolicy, random_access_iterator I1, sized_sentinel_for<I1> S1,
         random_access_iterator I2, sized_sentinel_for<I2> S2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
  bool ranges::starts_with(ExecutionPolicy&& exec, I1 first1, S1 last1, I2 first2, S2 last2,
                           Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_range R1, random_access_range R2, class Pred = ranges::equal_to,
         class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2> &&
    sized_range<R1> && sized_range<R2>
  bool ranges::starts_with(ExecutionPolicy&& exec, R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {});

Returns: ranges::mismatch(std::forward<ExecutionPolicy>(exec), std::move(first1), last1, std::move(first2), last2, pred, proj1, proj2).in2 == last2

7.18. Modify ends_with in [alg.ends.with]

template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires (forward_iterator<I1> || sized_sentinel_for<S1, I1>) &&
           (forward_iterator<I2> || sized_sentinel_for<S2, I2>) &&
           indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
  constexpr bool ranges::ends_with(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
                                   Proj1 proj1 = {}, Proj2 proj2 = {});

Let N1 be last1 - first1 and N2 be last2 - first2.

Returns: false if N1 < N2, otherwise ranges::equal(std::move(first1) + (N1 - N2), last1, std::move(first2), last2, pred, proj1, proj2)

template<class ExecutionPolicy, random_access_iterator I1, sized_sentinel_for<I1> S1, random_access_iterator I2, sized_sentinel_for<I2> S2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
  bool ranges::ends_with(ExecutionPolicy&& exec, I1 first1, S1 last1, I2 first2, S2 last2,
                         Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {});

Let N1 be last1 - first1 and N2 be last2 - first2.

Returns: false if N1 < N2, otherwise ranges::equal(std::forward<ExecutionPolicy>(exec), std::move(first1) + (N1 - N2), last1, std::move(first2), last2, pred, proj1, proj2)

template<input_range R1, input_range R2, class Pred = ranges::equal_to, class Proj1 = identity,
         class Proj2 = identity>
  requires (forward_range<R1> || sized_range<R1>) &&
           (forward_range<R2> || sized_range<R2>) &&
           indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
  constexpr bool ranges::ends_with(R1&& r1, R2&& r2, Pred pred = {},
                                   Proj1 proj1 = {}, Proj2 proj2 = {});

Let N1 be ranges::distance(r1) and N2 be ranges::distance(r2).

Returns: false if N1 < N2, otherwise ranges::equal(views::drop(ranges::ref_view(r1), N1 - static_cast<decltype(N1)>(N2)), r2, pred, proj1, proj2)

template<class ExecutionPolicy, random_access_range R1, random_access_range R2,
         class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
  requires (sized_range<R1> && sized_range<R2>) &&
           indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2>
  bool ranges::ends_with(ExecutionPolicy&& exec, R1&& r1, R2&& r2,
                         Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {});

Let N1 be ranges::distance(r1) and N2 be ranges::distance(r2).

Returns: false if N1 < N2, otherwise ranges::equal(std::forward<ExecutionPolicy>, views::drop(ranges::ref_view(r1), N1 - static_cast<decltype(N1)>(N2)), r2, pred, proj1, proj2)

7.19. Modify copy in [alg.copy]

template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2>
  ForwardIterator2 copy(ExecutionPolicy&& policy,
                        ForwardIterator1 first, ForwardIterator1 last,
                        ForwardIterator2 result);
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, random_access_iterator O>
  requires indirectly_copyable<I, O>
  ranges::copy_result<I, O> ranges::copy(ExecutionPolicy&& exec, I first, S last, O result);
template<class ExecutionPolicy, random_access_range R, random_access_iterator O>
  requires indirectly_copyable<iterator_t<R>, O> && sized_range<R>
  ranges::copy_result<borrowed_iterator_t<R>, O> ranges::copy(ExecutionPolicy&& exec, R&& r, O result);
template<input_iterator I, weakly_incrementable O>
  requires indirectly_copyable<I, O>
  constexpr ranges::copy_n_result<I, O>
    ranges::copy_n(I first, iter_difference_t<I> n, O result);
template<class ExecutionPolicy, random_access_iterator I, random_access_iterator O>
  requires indirectly_copyable<I, O>
  ranges::copy_n_result<I, O>
    ranges::copy_n(ExecutionPolicy&& exec, I first, iter_difference_t<I> n, O result);
template<input_iterator I, sentinel_for<I> S, weakly_incrementable O, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  requires indirectly_copyable<I, O>
  constexpr ranges::copy_if_result<I, O>
    ranges::copy_if(I first, S last, O result, Pred pred, Proj proj = {});
template<input_range R, weakly_incrementable O, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires indirectly_copyable<iterator_t<R>, O>
  constexpr ranges::copy_if_result<borrowed_iterator_t<R>, O>
    ranges::copy_if(R&& r, O result, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, random_access_iterator O,
         class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
  requires indirectly_copyable<I, O>
  ranges::copy_if_result<I, O>
    ranges::copy_if(ExecutionPolicy&& exec, I first, S last, O result,
                    Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, random_access_iterator O,
         class Proj = identity, indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires indirectly_copyable<iterator_t<R>, O> && sized_range<R>
  ranges::copy_if_result<borrowed_iterator_t<R>, O>
    ranges::copy_if(ExecutionPolicy&& exec, R&& r, O result, Pred pred, Proj proj = {});

7.20. Modify move in [alg.move]

template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2>
  ForwardIterator2 move(ExecutionPolicy&& policy,
                        ForwardIterator1 first, ForwardIterator1 last,
                        ForwardIterator2 result);
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, random_access_iterator O>
  requires indirectly_movable<I, O>
  ranges::move_result<I, O> ranges::move(ExecutionPolicy&& exec, I first, S last, O result);
template<class ExecutionPolicy, random_access_range R, random_access_iterator O>
  requires indirectly_movable<iterator_t<R>, O> && sized_range<R>
  ranges::move_result<borrowed_iterator_t<R>, O> ranges::move(ExecutionPolicy&& exec, R&& r, O result);

7.21. Modify swap in [alg.swap]

template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2>
  requires indirectly_swappable<I1, I2>
  constexpr ranges::swap_ranges_result<I1, I2>
    ranges::swap_ranges(I1 first1, S1 last1, I2 first2, S2 last2);
template<input_range R1, input_range R2>
  requires indirectly_swappable<iterator_t<R1>, iterator_t<R2>>
  constexpr ranges::swap_ranges_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>>
    ranges::swap_ranges(R1&& r1, R2&& r2);
template<class ExecutionPolicy, random_access_iterator I1, sized_sentinel_for<I1> S1, random_access_iterator I2, sized_sentinel_for<I2> S2>
  requires indirectly_swappable<I1, I2>
  ranges::swap_ranges_result<I1, I2>
    ranges::swap_ranges(ExecutionPolicy&& exec, I1 first1, S1 last1, I2 first2, S2 last2);
template<class ExecutionPolicy, random_access_range R1, random_access_range R2>
  requires indirectly_swappable<iterator_t<R1>, iterator_t<R2>> && sized_range<R1> && sized_range<R2>
  ranges::swap_ranges_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>>
    ranges::swap_ranges(ExecutionPolicy&& exec, R1&& r1, R2&& r2);

7.22. Modify transform in [alg.transform]

template<input_iterator I, sentinel_for<I> S, weakly_incrementable O,
         copy_constructible F, class Proj = identity>
  requires indirectly_writable<O, indirect_result_t<F&, projected<I, Proj>>>
  constexpr ranges::unary_transform_result<I, O>
    ranges::transform(I first1, S last1, O result, F op, Proj proj = {});
template<input_range R, weakly_incrementable O, copy_constructible F,
         class Proj = identity>
  requires indirectly_writable<O, indirect_result_t<F&, projected<iterator_t<R>, Proj>>>
  constexpr ranges::unary_transform_result<borrowed_iterator_t<R>, O>
    ranges::transform(R&& r, O result, F op, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, random_access_iterator O,
         copy_constructible F, class Proj = identity>
  requires indirectly_writable<O, indirect_result_t<F&, projected<I, Proj>>>
  ranges::unary_transform_result<I, O>
    ranges::transform(ExecutionPolicy&& exec, I first, S last, O result,
                      F op, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, random_access_iterator O,
         copy_constructible F, class Proj = identity>
  requires indirectly_writable<O, indirect_result_t<F&, projected<iterator_t<R>, Proj>>> && sized_range<R>
  ranges::unary_transform_result<borrowed_iterator_t<R>, O>
    ranges::transform(ExecutionPolicy&& exec, R&& r, O result, F op, Proj proj = {});
template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
         weakly_incrementable O, copy_constructible F, class Proj1 = identity,
         class Proj2 = identity>
  requires indirectly_writable<O, indirect_result_t<F&, projected<I1, Proj1>,
                                         projected<I2, Proj2>>>
  constexpr ranges::binary_transform_result<I1, I2, O>
    ranges::transform(I1 first1, S1 last1, I2 first2, S2 last2, O result,
                      F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, input_range R2, weakly_incrementable O,
         copy_constructible F, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_writable<O, indirect_result_t<F&, projected<iterator_t<R1>, Proj1>,
                                         projected<iterator_t<R2>, Proj2>>>
  constexpr ranges::binary_transform_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O>
    ranges::transform(R1&& r1, R2&& r2, O result,
                      F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_iterator I1, sentinel_for<I1> S1, random_access_iterator I2, sentinel_for<I2> S2,
         random_access_iterator O, copy_constructible F, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_writable<O, indirect_result_t<F&, projected<I1, Proj1>, projected<I2, Proj2>>> &&
    (sized_sentinel_for<S1, I1> || sized_sentinel_for<S2, I2>)
  ranges::binary_transform_result<I1, I2, O>
    ranges::transform(ExecutionPolicy&& exec, I1 first1, S1 last1, I2 first2, S2 last2, O result,
                      F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_range R1, random_access_range R2, random_access_iterator O,
         copy_constructible F, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_writable<O, indirect_result_t<F&, projected<iterator_t<R1>, Proj1>,
    projected<iterator_t<R2>, Proj2>>> && (sized_range<R1> || sized_range<R2>)
  ranges::binary_transform_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O>
    ranges::transform(ExecutionPolicy&& exec, R1&& r1, R2&& r2, O result,
                      F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {});

7.23. Modify replace in [alg.replace]

template<input_iterator I, sentinel_for<I> S, class Proj = identity,
         class T1 = projected_value_t<I, Proj>, class T2 = T1>
  requires indirectly_writable<I, const T2&> &&
           indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T1*>
  constexpr I
    ranges::replace(I first, S last, const T1& old_value, const T2& new_value, Proj proj = {});
template<input_range R, class Proj = identity,
         class T1 = projected_value_t<iterator_t<R>, Proj>, class T2 = T1>
  requires indirectly_writable<iterator_t<R>, const T2&> &&
           indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T1*>
  constexpr borrowed_iterator_t<R>
    ranges::replace(R&& r, const T1& old_value, const T2& new_value, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         class T1 = projected_value_t<I, Proj>, class T2 = T1>
  requires indirectly_writable<I, const T2&> &&
           indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T1*>
  I ranges::replace(ExecutionPolicy&& exec, I first, S last,
                    const T1& old_value, const T2& new_value, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         class T1 = projected_value_t<iterator_t<R>, Proj>, class T2 = T1>
  requires indirectly_writable<iterator_t<R>, const T2&> &&
           indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T1*> &&
           sized_range<R>
  borrowed_iterator_t<R>
    ranges::replace(ExecutionPolicy&& exec, R&& r,
                    const T1& old_value, const T2& new_value, Proj proj = {});
template<input_iterator I, sentinel_for<I> S, class Proj = identity,
         class T = projected_value_t<I, Proj>,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  requires indirectly_writable<I, const T&>
  constexpr I ranges::replace_if(I first, S last, Pred pred, const T& new_value, Proj proj = {});
template<input_range R, class Proj = identity, class T = projected_value_t<iterator_t<R>, Proj>,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires indirectly_writable<iterator_t<R>, const T&>
  constexpr borrowed_iterator_t<R>
    ranges::replace_if(R&& r, Pred pred, const T& new_value, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         class T = projected_value_t<I, Proj>,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  requires indirectly_writable<I, const T&>
  I ranges::replace_if(ExecutionPolicy&& exec, I first, S last, Pred pred,
                       const T& new_value, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         class T = projected_value_t<iterator_t<R>, Proj>,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires indirectly_writable<iterator_t<R>, const T&> && sized_range<R>
  borrowed_iterator_t<R>
    ranges::replace_if(ExecutionPolicy&& exec, R&& r, Pred pred,
                       const T& new_value, Proj proj = {});
template<input_iterator I, sentinel_for<I> S, class O,
         class Proj = identity, class T1 = projected_value_t<I, Proj>, class T2 = iter_value_t<O>>
  requires indirectly_copyable<I, O> &&
           indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T1*> &&
           output_iterator<O, const T2&>
  constexpr ranges::replace_copy_result<I, O>
    ranges::replace_copy(I first, S last, O result, const T1& old_value, const T2& new_value,
                         Proj proj = {});
template<input_range R, class O, class Proj = identity,
         class T1 = projected_value_t<iterator_t<R>, Proj>, class T2 = iter_value_t<O>>
  requires indirectly_copyable<iterator_t<R>, O> &&
           indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T1*>
           && output_iterator<O, const T2&>
  constexpr ranges::replace_copy_result<borrowed_iterator_t<R>, O>
    ranges::replace_copy(R&& r, O result, const T1& old_value, const T2& new_value,
                         Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, random_access_iterator O,
         class Proj = identity, class T1 = projected_value_t<I, Proj>, class T2 = iter_value_t<O>>
  requires indirectly_copyable<I, O> &&
           indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T1*> &&
           indirectly_writable<O, const T2&>
  ranges::replace_copy_result<I, O>
    ranges::replace_copy(ExecutionPolicy&& exec, I first, S last, O result,
                         const T1& old_value, const T2& new_value, Proj proj = {});

template<class ExecutionPolicy, random_access_range R, random_access_iterator O,
         class Proj = identity, class T1 = projected_value_t<iterator_t<R>, Proj>,
         class T2 = iter_value_t<O>>
  requires indirectly_copyable<iterator_t<R>, O> &&
           indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T1*> &&
           indirectly_writable<O, const T2&> && sized_range<R>
  ranges::replace_copy_result<borrowed_iterator_t<R>, O>
    ranges::replace_copy(ExecutionPolicy&& exec, R&& r, O result,
                         const T1& old_value, const T2& new_value, Proj proj = {});
template<input_iterator I, sentinel_for<I> S,class O, class T = iter_value_t<O>,
         class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
  requires indirectly_copyable<I, O> && output_iterator<O, const T&>
  constexpr ranges::replace_copy_if_result<I, O>
    ranges::replace_copy_if(I first, S last, O result, Pred pred, const T& new_value,
                            Proj proj = {});
template<input_range R, class O, class T = iter_value_t<O>, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires indirectly_copyable<iterator_t<R>, O> && output_iterator<O, const T&>
  constexpr ranges::replace_copy_if_result<borrowed_iterator_t<R>, O>
    ranges::replace_copy_if(R&& r, O result, Pred pred, const T& new_value,
                            Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, random_access_iterator O,
         class T = iter_value_t<O>, class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
  requires indirectly_copyable<I, O> && indirectly_writable<O, const T&>
  ranges::replace_copy_if_result<I, O>
    ranges::replace_copy_if(ExecutionPolicy&& exec, I first, S last, O result,
                              Pred pred, const T& new_value, Proj proj = {});

template<class ExecutionPolicy, random_access_range R, random_access_iterator O,
         class T = iter_value_t<O>, class Proj = identity, indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires indirectly_copyable<iterator_t<R>, O> && indirectly_writable<O, const T&>&&
           sized_range<R>
  ranges::replace_copy_if_result<borrowed_iterator_t<R>, O>
    ranges::replace_copy_if(ExecutionPolicy&& exec, R&& r, O result,
                            Pred pred, const T& new_value, Proj proj = {});

7.24. Modify fill in [alg.fill]

template<class O, sentinel_for<O> S, class T = iter_value_t<O>>
  requires output_iterator<O, const T&>
  constexpr O ranges::fill(O first, S last, const T& value);
template<class R, class T = range_value_t<R>>
  requires output_range<R, const T&>
  constexpr borrowed_iterator_t<R> ranges::fill(R&& r, const T& value);
template<class O, class T = iter_value_t<O>>
  requires output_iterator<O, const T&>
  constexpr O ranges::fill_n(O first, iter_difference_t<O> n, const T& value);
template<class ExecutionPolicy, random_access_iterator O, sized_sentinel_for<O> S,
         class T = iter_value_t<O>>
  requires output_iterator<O, const T&>
  O ranges::fill(ExecutionPolicy&& exec, O first, S last, const T& value);
template<class ExecutionPolicy, random_access_range R, class T = range_value_t<R>>
  requires output_range<R, const T&> && sized_range<R>
  borrowed_iterator_t<R> ranges::fill(ExecutionPolicy&& exec, R&& r, const T& value);
template<class ExecutionPolicy, random_access_iterator O, class T = iter_value_t<O>>
    requires indirectly_writable<O, const T&>
  O ranges::fill_n(ExecutionPolicy&& exec, O first, iter_difference_t<O> n, const T& value);

7.25. Modify generate in [alg.generate]

template<input_or_output_iterator O, sentinel_for<O> S, copy_constructible F>
  requires invocable<F&> && indirectly_writable<O, invoke_result_t<F&>>
  constexpr O ranges::generate(O first, S last, F gen);
template<class R, copy_constructible F>
  requires invocable<F&> && output_range<R, invoke_result_t<F&>>
  constexpr borrowed_iterator_t<R> ranges::generate(R&& r, F gen);
template<input_or_output_iterator O, copy_constructible F>
  requires invocable<F&> && indirectly_writable<O, invoke_result_t<F&>>
  constexpr O ranges::generate_n(O first, iter_difference_t<O> n, F gen);
template<class ExecutionPolicy, random_access_iterator O, sized_sentinel_for<O> S, copy_constructible F>
  requires invocable<F&> && indirectly_writable<O, invoke_result_t<F&>>
  O ranges::generate(ExecutionPolicy&& exec, O first, S last, F gen);
template<class ExecutionPolicy, random_access_range R, copy_constructible F>
  requires invocable<F&> && output_range<R, invoke_result_t<F&>> && sized_range<R>
  borrowed_iterator_t<R> ranges::generate(ExecutionPolicy&& exec, R&& r, F gen);
template<class ExecutionPolicy, random_access_iterator O, copy_constructible F>
  requires invocable<F&> && indirectly_writable<O, invoke_result_t<F&>>
  O ranges::generate_n(ExecutionPolicy&& exec, O first, iter_difference_t<O> n, F gen);

7.26. Modify remove in [alg.remove]

template<permutable I, sentinel_for<I> S, class Proj = identity,
         class T = projected_value_t<I, Proj>>
  requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
  constexpr subrange<I> ranges::remove(I first, S last, const T& value, Proj proj = {});
template<forward_range R, class Proj = identity,
         class T = projected_value_t<iterator_t<R>, Proj>>
  requires permutable<iterator_t<R>> &&
           indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T*>
  constexpr borrowed_subrange_t<R>
    ranges::remove(R&& r, const T& value, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         class T = projected_value_t<I, Proj>>
  requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
  subrange<I> ranges::remove(ExecutionPolicy&& exec, I first, S last, const T& value, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         class T = projected_value_t<iterator_t<R>, Proj>>
  requires permutable<iterator_t<R>> &&
           indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T*> &&
           sized_range<R>
  borrowed_subrange_t<R> ranges::remove(ExecutionPolicy&& exec, R&& r, const T& value, Proj proj = {});
template<permutable I, sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  constexpr subrange<I> ranges::remove_if(I first, S last, Pred pred, Proj proj = {});
template<forward_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires permutable<iterator_t<R>>
  constexpr borrowed_subrange_t<R>
    ranges::remove_if(R&& r, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  subrange<I> ranges::remove_if(ExecutionPolicy&& exec, I first, S last, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires permutable<iterator_t<R>> && sized_range<R>
  borrowed_subrange_t<R> ranges::remove_if(ExecutionPolicy&& exec, R&& r, Pred pred, Proj proj = {});
template<input_iterator I, sentinel_for<I> S, weakly_incrementable O,
         class Proj = identity, class T = projected_value_t<I, Proj>>
  requires indirectly_copyable<I, O> &&
           indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
  constexpr ranges::remove_copy_result<I, O>
    ranges::remove_copy(I first, S last, O result, const T& value, Proj proj = {});
template<input_range R, weakly_incrementable O, class Proj = identity,
         class T = projected_value_t<iterator_t<R>, Proj>>
  requires indirectly_copyable<iterator_t<R>, O> &&
           indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T*>
  constexpr ranges::remove_copy_result<borrowed_iterator_t<R>, O>
    ranges::remove_copy(R&& r, O result, const T& value, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, random_access_iterator O,
         class Proj = identity, class T = projected_value_t<I, Proj>>
  requires indirectly_copyable<I, O> &&
           indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
  ranges::remove_copy_result<I, O>
    ranges::remove_copy(ExecutionPolicy&& exec, I first, S last, O result, const T& value, Proj proj = {});

template<class ExecutionPolicy, random_access_range R, random_access_iterator O, class Proj = identity,
         class T = projected_value_t<iterator_t<R>, Proj>>
  requires indirectly_copyable<iterator_t<R>, O> &&
           indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T*> && sized_range<R>
  ranges::remove_copy_result<borrowed_iterator_t<R>, O>
    ranges::remove_copy(ExecutionPolicy&& exec, R&& r, O result, const T& value, Proj proj = {});
template<input_iterator I, sentinel_for<I> S, weakly_incrementable O,
         class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
  requires indirectly_copyable<I, O>
  constexpr ranges::remove_copy_if_result<I, O>
    ranges::remove_copy_if(I first, S last, O result, Pred pred, Proj proj = {});
template<input_range R, weakly_incrementable O, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires indirectly_copyable<iterator_t<R>, O>
  constexpr ranges::remove_copy_if_result<borrowed_iterator_t<R>, O>
    ranges::remove_copy_if(R&& r, O result, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, random_access_iterator O,
         class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
  requires indirectly_copyable<I, O>
  ranges::remove_copy_if_result<I, O>
    ranges::remove_copy_if(ExecutionPolicy&& exec, I first, S last, O result, Pred pred, Proj proj = {});

template<class ExecutionPolicy, random_access_range R, random_access_iterator O, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires indirectly_copyable<iterator_t<R>, O> && sized_range<R>
  ranges::remove_copy_if_result<borrowed_iterator_t<R>, O>
    ranges::remove_copy_if(ExecutionPolicy&& exec, R&& r, O result, Pred pred, Proj proj = {});

7.27. Modify unique in [alg.unique]

template<permutable I, sentinel_for<I> S, class Proj = identity,
         indirect_equivalence_relation<projected<I, Proj>> C = ranges::equal_to>
  constexpr subrange<I> ranges::unique(I first, S last, C comp = {}, Proj proj = {});
template<forward_range R, class Proj = identity,
         indirect_equivalence_relation<projected<iterator_t<R>, Proj>> C = ranges::equal_to>
  requires permutable<iterator_t<R>>
  constexpr borrowed_subrange_t<R>
    ranges::unique(R&& r, C comp = {}, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         indirect_equivalence_relation<projected<I, Proj>> C = ranges::equal_to>
  requires permutable<I>
  subrange<I> ranges::unique(ExecutionPolicy&& exec, I first, S last, C comp = {}, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_equivalence_relation<projected<iterator_t<R>, Proj>> C = ranges::equal_to>
  requires permutable<iterator_t<R>> && sized_range<R>
  borrowed_subrange_t<R> ranges::unique(ExecutionPolicy&& exec, R&& r, C comp = {}, Proj proj = {});
template<input_iterator I, sentinel_for<I> S, weakly_incrementable O, class Proj = identity,
         indirect_equivalence_relation<projected<I, Proj>> C = ranges::equal_to>
  requires indirectly_copyable<I, O> &&
           (forward_iterator<I> ||
            (input_iterator<O> && same_as<iter_value_t<I>, iter_value_t<O>>) ||
            indirectly_copyable_storable<I, O>)
  constexpr ranges::unique_copy_result<I, O>
    ranges::unique_copy(I first, S last, O result, C comp = {}, Proj proj = {});
template<input_range R, weakly_incrementable O, class Proj = identity,
         indirect_equivalence_relation<projected<iterator_t<R>, Proj>> C = ranges::equal_to>
  requires indirectly_copyable<iterator_t<R>, O> &&
           (forward_iterator<iterator_t<R>> ||
            (input_iterator<O> && same_as<range_value_t<R>, iter_value_t<O>>) ||
            indirectly_copyable_storable<iterator_t<R>, O>)
  constexpr ranges::unique_copy_result<borrowed_iterator_t<R>, O>
    ranges::unique_copy(R&& r, O result, C comp = {}, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, random_access_iterator O,
         class Proj = identity, indirect_equivalence_relation<projected<I, Proj>> C = ranges::equal_to>
  requires indirectly_copyable<I, O>
  ranges::unique_copy_result<I, O>
    ranges::unique_copy(ExecutionPolicy&& exec, I first, S last, O result,
                        C comp = {}, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, random_access_iterator O, class Proj = identity,
         indirect_equivalence_relation<projected<iterator_t<R>, Proj>> C = ranges::equal_to>
  requires indirectly_copyable<iterator_t<R>, O> && sized_range<R>
  ranges::unique_copy_result<borrowed_iterator_t<R>, O>
    ranges::unique_copy(ExecutionPolicy&& exec, R&& r, O result,
                        C comp = {}, Proj proj = {});

7.28. Modify reverse in [alg.reverse]

template<bidirectional_iterator I, sentinel_for<I> S>
  requires permutable<I>
  constexpr I ranges::reverse(I first, S last);
template<bidirectional_range R>
  requires permutable<iterator_t<R>>
  constexpr borrowed_iterator_t<R> ranges::reverse(R&& r);
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S>
  requires permutable<I>
  I ranges::reverse(ExecutionPolicy&& exec, I first, S last);
template<class ExecutionPolicy, random_access_range R>
  requires permutable<iterator_t<R>> && sized_range<R>
  borrowed_iterator_t<R> ranges::reverse(ExecutionPolicy&& exec, R&& r);
template<bidirectional_iterator I, sentinel_for<I> S, weakly_incrementable O>
  requires indirectly_copyable<I, O>
  constexpr ranges::reverse_copy_result<I, O>
    ranges::reverse_copy(I first, S last, O result);
template<bidirectional_range R, weakly_incrementable O>
  requires indirectly_copyable<iterator_t<R>, O>
  constexpr ranges::reverse_copy_result<borrowed_iterator_t<R>, O>
    ranges::reverse_copy(R&& r, O result);
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, random_access_iterator O>
  requires indirectly_copyable<I, O>
  ranges::reverse_copy_result<I, O>
    ranges::reverse_copy(ExecutionPolicy&& exec, I first, S last, O result);
template<class ExecutionPolicy, random_access_range R, random_access_iterator O>
  requires indirectly_copyable<iterator_t<R>, O> && sized_range<R>
  ranges::reverse_copy_result<borrowed_iterator_t<R>, O>
    ranges::reverse_copy(ExecutionPolicy&& exec, R&& r, O result);

7.29. Modify rotate in [alg.rotate]

template<permutable I, sentinel_for<I> S>
  constexpr subrange<I> ranges::rotate(I first, I middle, S last);
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S>
  requires permutable<I>
  subrange<I> ranges::rotate(ExecutionPolicy&& exec, I first, I middle, S last);
template<forward_range R>
  requires permutable<iterator_t<R>>
  constexpr borrowed_subrange_t<R> ranges::rotate(R&& r, iterator_t<R> middle);

Effects: Equivalent to: return ranges::rotate(ranges::begin(r), middle, ranges::end(r));

template<class ExecutionPolicy, random_access_range R>
  requires permutable<iterator_t<R>> && sized_range<R>
  borrowed_subrange_t<R> ranges::rotate(ExecutionPolicy&& exec, R&& r, iterator_t<R> middle);

Effects: Equivalent to: return ranges::rotate(std::forward<ExecutionPolicy>(exec), ranges::begin(r), middle, ranges::end(r));

template<forward_iterator I, sentinel_for<I> S, weakly_incrementable O>
    requires indirectly_copyable<I, O>
    constexpr ranges::rotate_copy_result<I, O>
      ranges::rotate_copy(I first, I middle, S last, O result);
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, random_access_iterator O>
  requires indirectly_copyable<I, O>
  ranges::rotate_copy_result<I, O> ranges::rotate_copy(ExecutionPolicy&& exec, I first, I middle, S last, O result);
template<forward_range R, weakly_incrementable O>
  requires indirectly_copyable<iterator_t<R>, O>
  constexpr ranges::rotate_copy_result<borrowed_iterator_t<R>, O>
    ranges::rotate_copy(R&& r, iterator_t<R> middle, O result);

Effects: Equivalent to: return ranges::rotate_copy(ranges::begin(r), middle, ranges::end(r), std::move(result));

template<class ExecutionPolicy, random_access_range R, random_access_iterator O>
  requires indirectly_copyable<iterator_t<R>, O> && sized_range<R>
  ranges::rotate_copy_result<borrowed_iterator_t<R>, O> ranges::rotate_copy(ExecutionPolicy&& exec, R&& r, iterator_t<R> middle, O result);

Effects: Equivalent to: return ranges::rotate_copy(std::forward<ExecutionPolicy>(exec), ranges::begin(r), middle, ranges::end(r), std::move(result));

7.30. Modify shift in [alg.shift]

template<permutable I, sentinel_for<I> S>
  constexpr subrange<I> ranges::shift_left(I first, S last, iter_difference_t<I> n);
template<forward_range R>
  requires permutable<iterator_t<R>>
  constexpr borrowed_subrange_t<R> ranges::shift_left(R&& r, range_difference_t<R> n)
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S>
  requires permutable<I>
  subrange<I> ranges::shift_left(ExecutionPolicy&& exec, I first, S last, iter_difference_t<I> n);
template<class ExecutionPolicy, random_access_range R>
  requires permutable<iterator_t<R>> && sized_range<R>
  borrowed_subrange_t<R> ranges::shift_left(ExecutionPolicy&& exec, R&& r, range_difference_t<R> n);
template<permutable I, sentinel_for<I> S>
  constexpr subrange<I> ranges::shift_right(I first, S last, iter_difference_t<I> n);
template<forward_range R>
  requires permutable<iterator_t<R>>
  constexpr borrowed_subrange_t<R> ranges::shift_right(R&& r, range_difference_t<R> n);
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S>
  requires permutable<I>
  subrange<I> ranges::shift_right(ExecutionPolicy&& exec, I first, S last, iter_difference_t<I> n);
template<class ExecutionPolicy, random_access_range R>
  requires permutable<iterator_t<R>> && sized_range<R>
  borrowed_subrange_t<R> ranges::shift_right(ExecutionPolicy&& exec, R&& r, range_difference_t<R> n);

7.31. Modify sort in [sort]

template<random_access_iterator I, sentinel_for<I> S, class Comp = ranges::less,
         class Proj = identity>
  requires sortable<I, Comp, Proj>
  constexpr I
    ranges::sort(I first, S last, Comp comp = {}, Proj proj = {});
template<random_access_range R, class Comp = ranges::less, class Proj = identity>
  requires sortable<iterator_t<R>, Comp, Proj>
  constexpr borrowed_iterator_t<R>
    ranges::sort(R&& r, Comp comp = {}, Proj proj = {});
template<ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Comp = ranges::less,
         class Proj = identity>
  requires sortable<I, Comp, Proj>
  I ranges::sort(ExecutionPolicy&& exec, I first, S last, Comp comp = {}, Proj proj = {});
template<ExecutionPolicy, random_access_range R, class Comp = ranges::less, class Proj = identity>
  requires sortable<iterator_t<R>, Comp, Proj> && sized_range<R>
  borrowed_iterator_t<R> ranges::sort(ExecutionPolicy&& exec, R&& r, Comp comp = {}, Proj proj = {});

7.32. Modify stable_sort in [stable.sort]

template<random_access_iterator I, sentinel_for<I> S, class Comp = ranges::less,
         class Proj = identity>
  requires sortable<I, Comp, Proj>
  constexpr I ranges::stable_sort(I first, S last, Comp comp = {}, Proj proj = {});
template<random_access_range R, class Comp = ranges::less, class Proj = identity>
  requires sortable<iterator_t<R>, Comp, Proj>
  constexpr borrowed_iterator_t<R>
    ranges::stable_sort(R&& r, Comp comp = {}, Proj proj = {});
template<ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Comp = ranges::less,
         class Proj = identity>
  requires sortable<I, Comp, Proj>
  I ranges::stable_sort(ExecutionPolicy&& exec, I first, S last, Comp comp = {}, Proj proj = {});
template<ExecutionPolicy, random_access_range R, class Comp = ranges::less, class Proj = identity>
  requires sortable<iterator_t<R>, Comp, Proj> && sized_range<R>
  borrowed_iterator_t<R> ranges::stable_sort(ExecutionPolicy&& exec, R&& r, Comp comp = {}, Proj proj = {});

7.33. Modify partial_sort in [partial.sort]

template<random_access_iterator I, sentinel_for<I> S, class Comp = ranges::less,
         class Proj = identity>
  requires sortable<I, Comp, Proj>
  constexpr I
    ranges::partial_sort(I first, I middle, S last, Comp comp = {}, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Comp = ranges::less,
         class Proj = identity>
  requires sortable<I, Comp, Proj>
  I ranges::partial_sort(ExecutionPolicy&& exec, I first, I middle, S last, Comp comp = {}, Proj proj = {});
template<random_access_range R, class Comp = ranges::less, class Proj = identity>
  requires sortable<iterator_t<R>, Comp, Proj>
  constexpr borrowed_iterator_t<R>
    ranges::partial_sort(R&& r, iterator_t<R> middle, Comp comp = {}, Proj proj = {});

Effects: Equivalent to: return ranges::partial_sort(ranges::begin(r), middle, ranges::end(r), comp, proj);

template<class ExecutionPolicy, random_access_range R, class Comp = ranges::less, class Proj = identity>
  requires sortable<iterator_t<R>, Comp, Proj> && sized_range<R>
  borrowed_iterator_t<R> ranges::partial_sort(ExecutionPolicy&& exec, R&& r, iterator_t<R> middle,
                                              Comp comp = {}, Proj proj = {});

Effects: Equivalent to:
return ranges::partial_sort(std::forward<ExecutionPolicy>(exec), ranges::begin(r), middle, ranges::end(r), comp, proj);

7.34. Modify partial_sort_copy in [partial.sort.copy]

template<input_iterator I1, sentinel_for<I1> S1, random_access_iterator I2, sentinel_for<I2> S2,
         class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_copyable<I1, I2> && sortable<I2, Comp, Proj2> &&
           indirect_strict_weak_order<Comp, projected<I1, Proj1>, projected<I2, Proj2>>
  constexpr ranges::partial_sort_copy_result<I1, I2>
    ranges::partial_sort_copy(I1 first, S1 last, I2 result_first, S2 result_last,
                              Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, random_access_range R2, class Comp = ranges::less,
         class Proj1 = identity, class Proj2 = identity>
  requires indirectly_copyable<iterator_t<R1>, iterator_t<R2>> &&
           sortable<iterator_t<R2>, Comp, Proj2> &&
           indirect_strict_weak_order<Comp, projected<iterator_t<R1>, Proj1>,
                                      projected<iterator_t<R2>, Proj2>>
  constexpr ranges::partial_sort_copy_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>>
    ranges::partial_sort_copy(R1&& r, R2&& result_r, Comp comp = {},
                              Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_range I1, sized_sentinel_for<I1> S1,
         random_access_iterator I2, sized_sentinel_for<I2> S2,
         class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
  requires indirectly_copyable<I1, I2> && sortable<I2, Comp, Proj2> &&
           indirect_strict_weak_order<Comp, projected<I1, Proj1>, projected<I2, Proj2>>
  ranges::partial_sort_copy_result<I1, I2>
    ranges::partial_sort_copy(ExecutionPolicy&& exec, I1 first, S1 last, I2 result_first, S2 result_last,
                              Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_range R1, random_access_range R2, class Comp = ranges::less,
         class Proj1 = identity, class Proj2 = identity>
  requires indirectly_copyable<iterator_t<R1>, iterator_t<R2>> &&
           sortable<iterator_t<R2>, Comp, Proj2> &&
           indirect_strict_weak_order<Comp, projected<iterator_t<R1>, Proj1>,
                                      projected<iterator_t<R2>, Proj2>> &&
           sized_range<R1> && sized_range<R2>
  ranges::partial_sort_copy_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>>
    ranges::partial_sort_copy(ExecutionPolicy&& exec, R1&& r, R2&& result_r, Comp comp = {},
                              Proj1 proj1 = {}, Proj2 proj2 = {});

7.35. Modify is_sorted in [is.sorted]

template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
         indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
  constexpr bool ranges::is_sorted(I first, S last, Comp comp = {}, Proj proj = {});
template<forward_range R, class Proj = identity,
         indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
  constexpr bool ranges::is_sorted(R&& r, Comp comp = {}, Proj proj = {});

Effects: Equivalent to: return ranges::is_sorted_until(first, last, comp, proj) == last;

template<ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
  bool ranges::is_sorted(ExecutionPolicy&& exec, I first, S last, Comp comp = {}, Proj proj = {});
template<ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
  requires sized_range<R>
  bool ranges::is_sorted(ExecutionPolicy&& exec, R&& r, Comp comp = {}, Proj proj = {});

Effects: Equivalent to:
return ranges::is_sorted_until(std::forward<ExecutionPolicy>(exec), first, last, comp, proj) == last;

template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
         indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
  constexpr I ranges::is_sorted_until(I first, S last, Comp comp = {}, Proj proj = {});
template<forward_range R, class Proj = identity,
         indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
  constexpr borrowed_iterator_t<R>
    ranges::is_sorted_until(R&& r, Comp comp = {}, Proj proj = {});
template<ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
  I ranges::is_sorted_until(ExecutionPolicy&& exec, I first, S last, Comp comp = {}, Proj proj = {});
template<ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
  requires sized_range<R>
  borrowed_iterator_t<R> ranges::is_sorted_until(ExecutionPolicy&& exec, R&& r, Comp comp = {}, Proj proj = {});

7.36. Modify nth_element in [alg.nth.element]

template<random_access_iterator I, sentinel_for<I> S, class Comp = ranges::less,
         class Proj = identity>
  requires sortable<I, Comp, Proj>
  constexpr I
    ranges::nth_element(I first, I nth, S last, Comp comp = {}, Proj proj = {});
template<ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Comp = ranges::less,
         class Proj = identity>
  requires sortable<I, Comp, Proj>
  I ranges::nth_element(ExecutionPolicy&& exec, I first, I nth, S last, Comp comp = {}, Proj proj = {});
template<random_access_range R, class Comp = ranges::less, class Proj = identity>
  requires sortable<iterator_t<R>, Comp, Proj>
  constexpr borrowed_iterator_t<R>
    ranges::nth_element(R&& r, iterator_t<R> nth, Comp comp = {}, Proj proj = {});

Effects: Equivalent to: return ranges::nth_element(ranges::begin(r), nth, ranges::end(r), comp, proj);

template<ExecutionPolicy, random_access_range R, class Comp = ranges::less, class Proj = identity>
  requires sortable<iterator_t<R>, Comp, Proj> && sized_range<R>
  borrowed_iterator_t<R> ranges::nth_element(ExecutionPolicy&& exec, R&& r, iterator_t<R> nth,
                                             Comp comp = {}, Proj proj = {});

Effects: Equivalent to: return ranges::nth_element(std::forward<ExecutionPolicy>(exec), ranges::begin(r), nth, ranges::end(r), comp, proj);

7.37. Modify partitions in [alg.partitions]

template<input_iterator I, sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  constexpr bool ranges::is_partitioned(I first, S last, Pred pred, Proj proj = {});
template<input_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  constexpr bool ranges::is_partitioned(R&& r, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  bool ranges::is_partitioned(ExecutionPolicy&& exec, I first, S last, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires sized_range<R>
  bool ranges::is_partitioned(ExecutionPolicy&& exec, R&& r, Pred pred, Proj proj = {});
template<permutable I, sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  constexpr subrange<I>
    ranges::partition(I first, S last, Pred pred, Proj proj = {});
template<forward_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires permutable<iterator_t<R>>
  constexpr borrowed_subrange_t<R>
    ranges::partition(R&& r, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  subrange<I> ranges::partition(ExecutionPolicy&& exec, I first, S last, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires permutable<iterator_t<R>> && sized_range<R>
  borrowed_subrange_t<R> ranges::partition(ExecutionPolicy&& exec, R&& r, Pred pred, Proj proj = {});
template<bidirectional_iterator I, sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  requires permutable<I>
  constexpr subrange<I> ranges::stable_partition(I first, S last, Pred pred, Proj proj = {});
template<bidirectional_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires permutable<iterator_t<R>>
  constexpr borrowed_subrange_t<R> ranges::stable_partition(R&& r, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         indirect_unary_predicate<projected<I, Proj>> Pred>
  requires permutable<I>
  subrange<I> ranges::stable_partition(ExecutionPolicy&& exec, I first, S last, Pred pred, Proj proj = {});

template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires permutable<iterator_t<R>> && sized_range<R>
  borrowed_subrange_t<R> ranges::stable_partition(ExecutionPolicy&& exec, R&& r, Pred pred, Proj proj = {});
template<input_iterator I, sentinel_for<I> S, weakly_incrementable O1, weakly_incrementable O2,
         class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
  requires indirectly_copyable<I, O1> && indirectly_copyable<I, O2>
  constexpr ranges::partition_copy_result<I, O1, O2>
    ranges::partition_copy(I first, S last, O1 out_true, O2 out_false, Pred pred,
                           Proj proj = {});
template<input_range R, weakly_incrementable O1, weakly_incrementable O2,
         class Proj = identity,
         indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires indirectly_copyable<iterator_t<R>, O1> &&
           indirectly_copyable<iterator_t<R>, O2>
  constexpr ranges::partition_copy_result<borrowed_iterator_t<R>, O1, O2>
    ranges::partition_copy(R&& r, O1 out_true, O2 out_false, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, random_access_iterator O1, random_access_iterator O2,
         class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
  requires indirectly_copyable<I, O1> && indirectly_copyable<I, O2>
  ranges::partition_copy_result<I, O1, O2>
    ranges::partition_copy(ExecutionPolicy&& exec, I first, S last, O1 out_true, O2 out_false, Pred pred, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, random_access_iterator O1, random_access_iterator O2,
         class Proj = identity, indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
  requires indirectly_copyable<iterator_t<R>, O1> && indirectly_copyable<iterator_t<R>, O2> && sized_range<R>
  ranges::partition_copy_result<borrowed_iterator_t<R>, O1, O2>
    ranges::partition_copy(ExecutionPolicy&& exec, R&& r, O1 out_true, O2 out_false, Pred pred, Proj proj = {});

7.38. Modify merge in [alg.merge]

template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
         weakly_incrementable O, class Comp = ranges::less, class Proj1 = identity,
         class Proj2 = identity>
  requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
  constexpr ranges::merge_result<I1, I2, O>
    ranges::merge(I1 first1, S1 last1, I2 first2, S2 last2, O result,
                  Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, input_range R2, weakly_incrementable O, class Comp = ranges::less,
         class Proj1 = identity, class Proj2 = identity>
  requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2>
  constexpr ranges::merge_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O>
    ranges::merge(R1&& r1, R2&& r2, O result,
                  Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_iterator I1, sized_sentinel_for<I1> S1,
         random_access_iterator I2, sized_sentinel_for<I2> S2,
         random_access_iterator O, class Comp = ranges::less, class Proj1 = identity,
         class Proj2 = identity>
  requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
  ranges::merge_result<I1, I2, O>
    ranges::merge(ExecutionPolicy&& exec, I1 first1, S1 last1, I2 first2, S2 last2, O result,
                  Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_range R1, random_access_range R2,
         random_access_iterator O, class Comp = ranges::less,
         class Proj1 = identity, class Proj2 = identity>
  requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2> && sized_range<R1> && sized_range<R2>
  ranges::merge_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O>
    ranges::merge(ExecutionPolicy&& exec, R1&& r1, R2&& r2, O result,
                  Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<bidirectional_iterator I, sentinel_for<I> S, class Comp = ranges::less,
         class Proj = identity>
  requires sortable<I, Comp, Proj>
  constexpr I ranges::inplace_merge(I first, I middle, S last, Comp comp = {}, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Comp = ranges::less,
         class Proj = identity>
  requires sortable<I, Comp, Proj>
  I ranges::inplace_merge(ExecutionPolicy&& exec, I first, I middle, S last, Comp comp = {}, Proj proj = {});
template<bidirectional_range R, class Comp = ranges::less, class Proj = identity>
  requires sortable<iterator_t<R>, Comp, Proj>
  constexpr borrowed_iterator_t<R>
    ranges::inplace_merge(R&& r, iterator_t<R> middle, Comp comp = {}, Proj proj = {});

Effects: Equivalent to: return ranges::inplace_merge(ranges::begin(r), middle, ranges::end(r), comp, proj);

template<class ExecutionPolicy, random_access_range R, class Comp = ranges::less, class Proj = identity>
  requires sortable<iterator_t<R>, Comp, Proj> && sized_range<R>
  borrowed_iterator_t<R> ranges::inplace_merge(ExecutionPolicy&& exec, R&& r, iterator_t<R> middle,
                                               Comp comp = {}, Proj proj = {});

Effects: Equivalent to:
return ranges::inplace_merge(std::forward<ExecutionPolicy>(exec), ranges::begin(r), middle, ranges::end(r), comp, proj);

7.39. Modify includes in [includes]

template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
         class Proj1 = identity, class Proj2 = identity,
         indirect_strict_weak_order<projected<I1, Proj1>,
                                    projected<I2, Proj2>> Comp = ranges::less>
  constexpr bool ranges::includes(I1 first1, S1 last1, I2 first2, S2 last2, Comp comp = {},
                                  Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, input_range R2, class Proj1 = identity,
         class Proj2 = identity,
         indirect_strict_weak_order<projected<iterator_t<R1>, Proj1>,
                                    projected<iterator_t<R2>, Proj2>> Comp = ranges::less>
  constexpr bool ranges::includes(R1&& r1, R2&& r2, Comp comp = {},
                                  Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_iterator I1, sized_sentinel_for<I1> S1, random_access_iterator I2, sized_sentinel_for<I2> S2,
         class Proj1 = identity, class Proj2 = identity,
         indirect_strict_weak_order<projected<I1, Proj1>, projected<I2, Proj2>> Comp = ranges::less>
  bool ranges::includes(ExecutionPolicy&& exec, I1 first1, S1 last1, I2 first2, S2 last2,
                        Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_range R1, random_access_range R2, class Proj1 = identity, class Proj2 = identity,
         indirect_strict_weak_order<projected<iterator_t<R1>, Proj1>, projected<iterator_t<R2>, Proj2>> Comp = ranges::less>
  requires sized_range<R1> && sized_range<R2>
  bool ranges::includes(ExecutionPolicy&& exec, R1&& r1, R2&& r2,
                        Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});

7.40. Modify set_union in [set.union]

template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
         weakly_incrementable O, class Comp = ranges::less,
         class Proj1 = identity, class Proj2 = identity>
  requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
  constexpr ranges::set_union_result<I1, I2, O>
    ranges::set_union(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {},
                      Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, input_range R2, weakly_incrementable O,
         class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
  requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2>
  constexpr ranges::set_union_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O>
    ranges::set_union(R1&& r1, R2&& r2, O result, Comp comp = {},
                      Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_iterator I1, sized_sentinel_for<I1> S1, random_access_iterator I2, sized_sentinel_for<I2> S2,
         random_access_iterator O, class Comp = ranges::less,
         class Proj1 = identity, class Proj2 = identity>
  requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
  ranges::set_union_result<I1, I2, O>
    ranges::set_union(ExecutionPolicy&& exec, I1 first1, S1 last1, I2 first2, S2 last2, O result,
                      Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_range R1, random_access_range R2, random_access_iterator O,
         class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
  requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2> && sized_range<R1> && sized_range<R2>
  ranges::set_union_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O>
    ranges::set_union(ExecutionPolicy&& exec, R1&& r1, R2&& r2, O result,
                      Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});

7.41. Modify set_intersection in [set.intersection]

template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
         weakly_incrementable O, class Comp = ranges::less,
         class Proj1 = identity, class Proj2 = identity>
  requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
  constexpr ranges::set_intersection_result<I1, I2, O>
    ranges::set_intersection(I1 first1, S1 last1, I2 first2, S2 last2, O result,
                             Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, input_range R2, weakly_incrementable O,
         class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
  requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2>
  constexpr ranges::set_intersection_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O>
    ranges::set_intersection(R1&& r1, R2&& r2, O result,
                             Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_iterator I1, sized_sentinel_for<I1> S1, random_access_iterator I2, sized_sentinel_for<I2> S2,
         random_access_iterator O, class Comp = ranges::less,
         class Proj1 = identity, class Proj2 = identity>
  requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
  ranges::set_intersection_result<I1, I2, O>
    ranges::set_intersection(ExecutionPolicy&& exec, I1 first1, S1 last1, I2 first2, S2 last2, O result,
                             Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});

template<class ExecutionPolicy, random_access_range R1, random_access_range R2, random_access_iterator O,
         class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
  requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2> && sized_range<R1> && sized_range<R2>
  ranges::set_intersection_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O>
    ranges::set_intersection(ExecutionPolicy&& exec, R1&& r1, R2&& r2, O result,
                             Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});

7.42. Modify set_difference in [set.difference]

template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
         weakly_incrementable O, class Comp = ranges::less,
         class Proj1 = identity, class Proj2 = identity>
  requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
  constexpr ranges::set_difference_result<I1, O>
    ranges::set_difference(I1 first1, S1 last1, I2 first2, S2 last2, O result,
                           Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, input_range R2, weakly_incrementable O,
         class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
  requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2>
  constexpr ranges::set_difference_result<borrowed_iterator_t<R1>, O>
    ranges::set_difference(R1&& r1, R2&& r2, O result,
                           Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_iterator I1, sized_sentinel_for<I1> S1, random_access_iterator I2, sized_sentinel_for<I2> S2,
         random_access_iterator O, class Comp = ranges::less,
         class Proj1 = identity, class Proj2 = identity>
  requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
  ranges::set_difference_result<I1, O>
    ranges::set_difference(ExecutionPolicy&& exec, I1 first1, S1 last1, I2 first2, S2 last2, O result,
                           Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});

template<class ExecutionPolicy, random_access_range R1, random_access_range R2, random_access_iterator O,
         class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
  requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2> && sized_range<R1> && sized_range<R2>
  ranges::set_difference_result<borrowed_iterator_t<R1>, O>
    ranges::set_difference(ExecutionPolicy&& exec, R1&& r1, R2&& r2, O result,
                           Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});

7.43. Modify set_symmetric_difference in [set.symmetric.difference]

template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
         weakly_incrementable O, class Comp = ranges::less,
         class Proj1 = identity, class Proj2 = identity>
  requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
  constexpr ranges::set_symmetric_difference_result<I1, I2, O>
    ranges::set_symmetric_difference(I1 first1, S1 last1, I2 first2, S2 last2, O result,
                                     Comp comp = {}, Proj1 proj1 = {},
                                     Proj2 proj2 = {});
template<input_range R1, input_range R2, weakly_incrementable O,
         class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
  requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2>
  constexpr ranges::set_symmetric_difference_result<borrowed_iterator_t<R1>,
                                                    borrowed_iterator_t<R2>, O>
    ranges::set_symmetric_difference(R1&& r1, R2&& r2, O result, Comp comp = {},
                                     Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_iterator I1, sized_sentinel_for<I1> S1, random_access_iterator I2, sized_sentinel_for<I2> S2,
         random_access_iterator O, class Comp = ranges::less,
         class Proj1 = identity, class Proj2 = identity>
  requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
  ranges::set_symmetric_difference_result<I1, I2, O>
    ranges::set_symmetric_difference(ExecutionPolicy&& exec, I1 first1, S1 last1, I2 first2, S2 last2, O result,
                                     Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});

template<class ExecutionPolicy, random_access_range R1, random_access_range R2, random_access_iterator O,
         class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
  requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2> && sized_range<R1> && sized_range<R2>
  ranges::set_symmetric_difference_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O>
    ranges::set_symmetric_difference(ExecutionPolicy&& exec, R1&& r1, R2&& r2, O result, Comp comp = {},
                                     Proj1 proj1 = {}, Proj2 proj2 = {});

7.44. Modify is_heap in [is.heap]

template<random_access_iterator I, sentinel_for<I> S, class Proj = identity,
         indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
  constexpr bool ranges::is_heap(I first, S last, Comp comp = {}, Proj proj = {});
template<random_access_range R, class Proj = identity,
         indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
  constexpr bool ranges::is_heap(R&& r, Comp comp = {}, Proj proj = {});

Effects: Equivalent to: return ranges::is_heap_until(first, last, comp, proj) == last;

template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
  bool ranges::is_heap(ExecutionPolicy&& exec, I first, S last, Comp comp = {}, Proj proj = {});

template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
  requires sized_range<R>
  bool ranges::is_heap(ExecutionPolicy&& exec, R&& r, Comp comp = {}, Proj proj = {});

Effects: Equivalent to: return ranges::is_heap_until(std::forward<ExecutionPolicy>(exec), first, last, comp, proj) == last;

template<random_access_iterator I, sentinel_for<I> S, class Proj = identity,
         indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
  constexpr I ranges::is_heap_until(I first, S last, Comp comp = {}, Proj proj = {});
template<random_access_range R, class Proj = identity,
         indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
  constexpr borrowed_iterator_t<R>
    ranges::is_heap_until(R&& r, Comp comp = {}, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
  I ranges::is_heap_until(ExecutionPolicy&& exec, I first, S last, Comp comp = {}, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
  requires sized_range<R>
  borrowed_iterator_t<R>
    ranges::is_heap_until(ExecutionPolicy&& exec, R&& r, Comp comp = {}, Proj proj = {});

7.45. Modify min, max, minmax in [alg.min.max]

template<input_range R, class Proj = identity,
         indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
  requires indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*>
  constexpr range_value_t<R>
    ranges::min(R&& r, Comp comp = {}, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
  requires sized_range<R> && indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*>
  range_value_t<R>
    ranges::min(ExecutionPolicy&& exec, R&& r, Comp comp = {}, Proj proj = {});
template<input_range R, class Proj = identity,
         indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
  requires indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*>
  constexpr range_value_t<R>
    ranges::max(R&& r, Comp comp = {}, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
  requires sized_range<R> && indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*>
  range_value_t<R>
    ranges::max(ExecutionPolicy&& exec, R&& r, Comp comp = {}, Proj proj = {});
template<input_range R, class Proj = identity,
         indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
  requires indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*>
  constexpr ranges::minmax_result<range_value_t<R>>
    ranges::minmax(R&& r, Comp comp = {}, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
  requires indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*> && sized_range<R>
  ranges::minmax_result<range_value_t<R>>
    ranges::minmax(ExecutionPolicy&& exec, R&& r, Comp comp = {}, Proj proj = {});
template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
         indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
  constexpr I ranges::min_element(I first, S last, Comp comp = {}, Proj proj = {});
template<forward_range R, class Proj = identity,
         indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
  constexpr borrowed_iterator_t<R>
    ranges::min_element(R&& r, Comp comp = {}, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
  I ranges::min_element(ExecutionPolicy&& exec, I first, S last, Comp comp = {}, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
  requires sized_range<R>
  borrowed_iterator_t<R>
    ranges::min_element(ExecutionPolicy&& exec, R&& r, Comp comp = {}, Proj proj = {});
template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
         indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
  constexpr I ranges::max_element(I first, S last, Comp comp = {}, Proj proj = {});
template<forward_range R, class Proj = identity,
         indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
  constexpr borrowed_iterator_t<R>
    ranges::max_element(R&& r, Comp comp = {}, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
  I ranges::max_element(ExecutionPolicy&& exec, I first, S last, Comp comp = {}, Proj proj = {});
template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
  requires sized_range<R>
  borrowed_iterator_t<R>
    ranges::max_element(ExecutionPolicy&& exec, R&& r, Comp comp = {}, Proj proj = {});
template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
         indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
  constexpr ranges::minmax_element_result<I>
    ranges::minmax_element(I first, S last, Comp comp = {}, Proj proj = {});
template<forward_range R, class Proj = identity,
         indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
  constexpr ranges::minmax_element_result<borrowed_iterator_t<R>>
    ranges::minmax_element(R&& r, Comp comp = {}, Proj proj = {});
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S, class Proj = identity,
         indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
  ranges::minmax_element_result<I>
    ranges::minmax_element(ExecutionPolicy&& exec, I first, S last, Comp comp = {}, Proj proj = {});

template<class ExecutionPolicy, random_access_range R, class Proj = identity,
         indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
  requires sized_range<R>
  ranges::minmax_element_result<borrowed_iterator_t<R>>
    ranges::minmax_element(ExecutionPolicy&& exec, R&& r, Comp comp = {}, Proj proj = {});

7.46. Modify lexicographical_compare in [alg.lex.comparison]

template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
         class Proj1 = identity, class Proj2 = identity,
         indirect_strict_weak_order<projected<I1, Proj1>,
                                    projected<I2, Proj2>> Comp = ranges::less>
  constexpr bool
    ranges::lexicographical_compare(I1 first1, S1 last1, I2 first2, S2 last2,
                                    Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});
template<input_range R1, input_range R2, class Proj1 = identity,
         class Proj2 = identity,
         indirect_strict_weak_order<projected<iterator_t<R1>, Proj1>,
                                    projected<iterator_t<R2>, Proj2>> Comp = ranges::less>
  constexpr bool
    ranges::lexicographical_compare(R1&& r1, R2&& r2, Comp comp = {},
                                    Proj1 proj1 = {}, Proj2 proj2 = {});
template<class ExecutionPolicy, random_access_iterator I1, sized_sentinel_for<I1> S1,
         random_access_iterator I2, sized_sentinel_for<I2> S2,
         class Proj1 = identity, class Proj2 = identity,
         indirect_strict_weak_order<projected<I1, Proj1>, projected<I2, Proj2>> Comp = ranges::less>
  bool ranges::lexicographical_compare(ExecutionPolicy&& exec, I1 first1, S1 last1, I2 first2, S2 last2,
                                       Comp comp = {}, Proj1 proj1 = {}, Proj2 proj2 = {});

template<class ExecutionPolicy, random_access_range R1, random_access_range R2, class Proj1 = identity,
         class Proj2 = identity,
         indirect_strict_weak_order<projected<iterator_t<R1>, Proj1>,
                                    projected<iterator_t<R2>, Proj2>> Comp = ranges::less>
  requires sized_range<R1> && sized_range<R2>
  bool ranges::lexicographical_compare(ExecutionPolicy&& exec, R1&& r1, R2&& r2, Comp comp = {},
                                       Proj1 proj1 = {}, Proj2 proj2 = {});

7.47. Modify [memory.syn]

// [specialized.algorithms], specialized algorithms
// [special.mem.concepts], special memory concepts
template<class I>
  concept nothrow-input-iterator = see below;       // exposition only
template<class I>
  concept nothrow-forward-iterator = see below;     // exposition only

template<class I>
  concept nothrow-random-access-iterator = see below;     // exposition only

template<class S, class I>
  concept nothrow-sentinel-for = see below;         // exposition only

template<class S, class I>
  concept nothrow-sized-sentinel-for = see below;   // exposition only

template<class R>
  concept nothrow-input-range = see below;          // exposition only
template<class R>
  concept nothrow-forward-range = see below;        // exposition only

template<class I>
  concept nothrow-random-access-range = see below;     // exposition only

template<nothrow-forward-iterator I, nothrow-sentinel-for<I> S>
  requires default_initializable<iter_value_t<I>>
    I uninitialized_default_construct(I first, S last);                         // freestanding
template<nothrow-forward-range R>
  requires default_initializable<range_value_t<R>>
    borrowed_iterator_t<R> uninitialized_default_construct(R&& r);              // freestanding

template<nothrow-forward-iterator I>
  requires default_initializable<iter_value_t<I>>
    I uninitialized_default_construct_n(I first, iter_difference_t<I> n);       // freestanding
template<class ExecutionPolicy, nothrow-random-access-iterator I, nothrow-sized-sentinel-for<I> S>
  requires default_initializable<iter_value_t<I>>
  I uninitialized_default_construct(ExecutionPolicy&& exec, I first, S last); // see [algorithms.parallel.overloads]

template<class ExecutionPolicy, nothrow-random-access-range R>
  requires default_initializable<range_value_t<R>> && sized_range<R>
  borrowed_iterator_t<R> uninitialized_default_construct(ExecutionPolicy&& exec, R&& r); // see [algorithms.parallel.overloads]

template<class ExecutionPolicy, nothrow-random-access-iterator I>
  requires default_initializable<iter_value_t<I>>
  I uninitialized_default_construct_n(ExecutionPolicy&& exec, I first, iter_difference_t<I> n); // see [algorithms.parallel.overloads]
template<nothrow-forward-iterator I, nothrow-sentinel-for<I> S>
  requires default_initializable<iter_value_t<I>>
    I uninitialized_value_construct(I first, S last);                           // freestanding
template<nothrow-forward-range R>
  requires default_initializable<range_value_t<R>>
    borrowed_iterator_t<R> uninitialized_value_construct(R&& r);                // freestanding

template<nothrow-forward-iterator I>
  requires default_initializable<iter_value_t<I>>
    I uninitialized_value_construct_n(I first, iter_difference_t<I> n);         // freestanding
template<class ExecutionPolicy, nothrow-random-access-iterator I, nothrow-sized-sentinel-for<I> S>
  requires default_initializable<iter_value_t<I>>
  I uninitialized_value_construct(ExecutionPolicy&& exec, I first, S last); // see [algorithms.parallel.overloads]

template<class ExecutionPolicy, nothrow-random-access-range R>
  requires default_initializable<range_value_t<R>> && sized_range<R>
  borrowed_iterator_t<R> uninitialized_value_construct(ExecutionPolicy&& exec, R&& r); // see [algorithms.parallel.overloads]

template<class ExecutionPolicy, nothrow-random-access-iterator I>
  requires default_initializable<iter_value_t<I>>
  I uninitialized_value_construct_n(ExecutionPolicy&& exec, I first, iter_difference_t<I> n); // see [algorithms.parallel.overloads]
template<input_iterator I, sentinel_for<I> S1,
          nothrow-forward-iterator O, nothrow-sentinel-for<O> S2>
  requires constructible_from<iter_value_t<O>, iter_reference_t<I>>
    uninitialized_copy_result<I, O>
      uninitialized_copy(I ifirst, S1 ilast, O ofirst, S2 olast);               // freestanding
template<input_range IR, nothrow-forward-range OR>
  requires constructible_from<range_value_t<OR>, range_reference_t<IR>>
    uninitialized_copy_result<borrowed_iterator_t<IR>, borrowed_iterator_t<OR>>
      uninitialized_copy(IR&& in_range, OR&& out_range);                        // freestanding

template<class I, class O>
  using uninitialized_copy_n_result = in_out_result<I, O>;                      // freestanding
template<input_iterator I, nothrow-forward-iterator O, nothrow-sentinel-for<O> S>
  requires constructible_from<iter_value_t<O>, iter_reference_t<I>>
    uninitialized_copy_n_result<I, O>
      uninitialized_copy_n(I ifirst, iter_difference_t<I> n,                    // freestanding
                           O ofirst, S olast);
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S1,
         nothrow-random-access-iterator O, nothrow-sized-sentinel-for<O> S2>
  requires constructible_from<iter_value_t<O>, iter_reference_t<I>>
    uninitialized_copy_result<I, O>
      uninitialized_copy(ExecutionPolicy&& exec, I ifirst, S1 ilast, O ofirst, S2 olast); // see [algorithms.parallel.overloads]
template<class ExecutionPolicy, random_access_range IR, nothrow-random-access-range OR>
  requires constructible_from<range_value_t<OR>, range_reference_t<IR>> && sized_range<IR> && sized_range<OR>
    uninitialized_copy_result<borrowed_iterator_t<IR>, borrowed_iterator_t<OR>>
      uninitialized_copy(ExecutionPolicy&& exec, IR&& in_range, OR&& out_range); // see [algorithms.parallel.overloads]

template<class ExecutionPolicy, random_access_iterator I, nothrow-random-access-iterator O,
         nothrow-sized-sentinel-for<O> S>
  requires constructible_from<iter_value_t<O>, iter_reference_t<I>>
    uninitialized_copy_n_result<I, O>
      uninitialized_copy_n(ExecutionPolicy&& exec, I ifirst, iter_difference_t<I> n, // see [algorithms.parallel.overloads]
                           O ofirst, S olast);
template<input_iterator I, sentinel_for<I> S1,
          nothrow-forward-iterator O, nothrow-sentinel-for<O> S2>
  requires constructible_from<iter_value_t<O>, iter_rvalue_reference_t<I>>
    uninitialized_move_result<I, O>
      uninitialized_move(I ifirst, S1 ilast, O ofirst, S2 olast);              // freestanding
template<input_range IR, nothrow-forward-range OR>
  requires constructible_from<range_value_t<OR>, range_rvalue_reference_t<IR>>
    uninitialized_move_result<borrowed_iterator_t<IR>, borrowed_iterator_t<OR>>
      uninitialized_move(IR&& in_range, OR&& out_range);                       // freestanding

template<input_iterator I,
          nothrow-forward-iterator O, nothrow-sentinel-for<O> S>
  requires constructible_from<iter_value_t<O>, iter_rvalue_reference_t<I>>
    uninitialized_move_n_result<I, O>
      uninitialized_move_n(I ifirst, iter_difference_t<I> n,                // freestanding
                           O ofirst, S olast);
template<class ExecutionPolicy, random_access_iterator I, sized_sentinel_for<I> S1,
         nothrow-random-access-iterator O, nothrow-sized-sentinel-for<O> S2>
  requires constructible_from<iter_value_t<O>, iter_rvalue_reference_t<I>>
    uninitialized_move_result<I, O>
      uninitialized_move(ExecutionPolicy&& exec, I ifirst, S1 ilast, O ofirst, S2 olast); // see [algorithms.parallel.overloads]

template<class ExecutionPolicy, random_access_range IR, nothrow-random-access-range OR>
  requires constructible_from<range_value_t<OR>, range_rvalue_reference_t<IR>> && sized_range<IR> && sized_range<OR>
    uninitialized_move_result<borrowed_iterator_t<IR>, borrowed_iterator_t<OR>>
      uninitialized_move(ExecutionPolicy&& exec, IR&& in_range, OR&& out_range);        // see [algorithms.parallel.overloads]

template<class ExecutionPolicy, random_access_iterator I,
    nothrow-random-access-iterator O, nothrow-sized-sentinel-for<O> S>
  requires constructible_from<iter_value_t<O>, iter_rvalue_reference_t<I>>
    uninitialized_move_n_result<I, O>
      uninitialized_move_n(ExecutionPolicy&& exec, I ifirst, iter_difference_t<I> n, // see [algorithms.parallel.overloads]
                           O ofirst, S olast);
template<nothrow-forward-iterator I, nothrow-sentinel-for<I> S, class T>
  requires constructible_from<iter_value_t<I>, const T&>
    I uninitialized_fill(I first, S last, const T& x);                          // freestanding
template<nothrow-forward-range R, class T>
  requires constructible_from<range_value_t<R>, const T&>
    borrowed_iterator_t<R> uninitialized_fill(R&& r, const T& x);               // freestanding

template<nothrow-forward-iterator I, class T>
  requires constructible_from<iter_value_t<I>, const T&>
    I uninitialized_fill_n(I first, iter_difference_t<I> n, const T& x);        // freestanding
template<class ExecutionPolicy, nothrow-random-access-iterator I, nothrow-sized-sentinel-for<I> S, class T>
  requires constructible_from<iter_value_t<I>, const T&>
    I uninitialized_fill(ExecutionPolicy&& exec, I first, S last, const T& x);                // see [algorithms.parallel.overloads]
template<class ExecutionPolicy, nothrow-random-access-range R, class T>
  requires constructible_from<range_value_t<R>, const T&> && sized_range<R>
    borrowed_iterator_t<R> uninitialized_fill(ExecutionPolicy&& exec, R&& r, const T& x);     // see [algorithms.parallel.overloads]

template<class ExecutionPolicy, nothrow-random-access-iterator I, class T>
  requires constructible_from<iter_value_t<I>, const T&>
    I uninitialized_fill_n(ExecutionPolicy&& exec, I first, iter_difference_t<I> n, const T& x); // see [algorithms.parallel.overloads]
template<nothrow-input-iterator I, nothrow-sentinel-for<I> S>
  requires destructible<iter_value_t<I>>
    constexpr I destroy(I first, S last) noexcept;                              // freestanding
template<nothrow-input-range R>
  requires destructible<range_value_t<R>>
    constexpr borrowed_iterator_t<R> destroy(R&& r) noexcept;                   // freestanding

template<nothrow-input-iterator I>
  requires destructible<iter_value_t<I>>
    constexpr I destroy_n(I first, iter_difference_t<I> n) noexcept;            // freestanding
template<class ExecutionPolicy, nothrow-random-access-iterator I, nothrow-sized-sentinel-for<I> S>
  requires destructible<iter_value_t<I>>
    I destroy(ExecutionPolicy&& exec, I first, S last) noexcept;                           // see [algorithms.parallel.overloads]

template<class ExecutionPolicy, nothrow-random-access-range R>
  requires destructible<range_value_t<R>> && sized_range<R>
    borrowed_iterator_t<R> destroy(ExecutionPolicy&& exec, R&& r) noexcept;                // see [algorithms.parallel.overloads]

template<class ExecutionPolicy, nothrow-random-access-iterator I>
  requires destructible<iter_value_t<I>>
    I destroy_n(ExecutionPolicy&& exec, I first, iter_difference_t<I> n) noexcept;         // see [algorithms.parallel.overloads]

7.48. Add exposition only concepts to [special.mem.concepts]

template<class S, class I>
concept nothrow-sentinel-for = sentinel_for<S, I>; // exposition only

Types S and I model nothrow-sentinel-for only if no exceptions are thrown from copy construction, move construction, copy assignment, move assignment, or comparisons between valid values of type I and S.

[Note X: This concept allows some sentinel_for ([iterator.concept.sentinel]) operations to throw exceptions. — end note]

template<class S, class I>
concept nothrow-sized-sentinel-for = sized_sentinel_for<S, I>; // exposition only

Types S and I model nothrow-sized-sentinel-for only if no exceptions are thrown from copy construction, move construction, copy assignment, move assignment, or comparisons between valid values of type I and S.

[Note X: This concept allows some sized_sentinel_for ([iterator.concept.sizedsentinel]) operations to throw exceptions. — end note]

template<class I>
concept nothrow-forward-iterator = // exposition only
  nothrow-input-iterator<I> &&
  forward_iterator<I> &&
  nothrow-sentinel-for<I, I>;

[Note X: This concept allows some forward_iterator ([iterator.concept.forward]) operations to throw exceptions. — end note]

template<class I>
concept nothrow-random-access-iterator = // exposition only
  nothrow-forward-iterator<I> &&
  random_access_iterator<I> &&
  nothrow-sentinel-for<I, I>;

[Note X: This concept allows some random_access_iterator ([iterator.concept.random.access]) operations to throw exceptions. — end note]

template<class R>
concept nothrow-forward-range = // exposition only
  nothrow-input-range<R> &&
  nothrow-forward-iterator<iterator_t<R>>;
template<class R>
concept nothrow-random-access-range = // exposition only
  nothrow-forward-range<R> &&
  nothrow-random-access-iterator<iterator_t<R>>;

8. Revision history

8.1. R2 => R3

8.2. R1 => R2

8.3. R0 => R1

9. Polls

9.1. Joint SG1 + SG9, St. Louis, 2024

Poll: Continue work on P3179R2 for IS’26 with these notes:

  1. RandomAccess for inputs and outputs

  2. Iterators for outputs

  3. We believe the overloads are worth it

SF F N A SA
7 4 2 1 0

9.2. SG9, Tokyo 2024

Poll 1: for_each shouldn’t return the callable

SF F N A SA
2 4 2 0 0

Poll 2: Parallel std::ranges algos should return the same type as serial std::ranges algos

Unanimous consent.

Poll 3: Parallel ranges algos should require forward_range, not random_access_range

SF F N A SA
3 2 3 1 1

Poll 4: Range-based parallel algos should require const operator()

SF F N A SA
0 7 2 0 0

References

Informative References

[P2300R9]
Eric Niebler, Michał Dominiak, Georgy Evtushenko, Lewis Baker, Lucian Radu Teodorescu, Lee Howes, Kirk Shoop, Michael Garland, Bryce Adelstein Lelbach. `std::execution`. 2 April 2024. URL: https://wg21.link/p2300r9
[P2408R5]
David Olsen. Ranges iterators as inputs to non-Ranges algorithms. 22 April 2022. URL: https://wg21.link/p2408r5
[P2500R2]
Ruslan Arutyunyan, Alexey Kukanov. C++ parallel algorithms and P2300. 15 October 2023. URL: https://wg21.link/p2500r2
[P2902R0]
Oliver Rosten. constexpr 'Parallel' Algorithms. 17 June 2023. URL: https://wg21.link/p2902r0
[P3136R0]
Tim Song. Retiring niebloids. 15 February 2024. URL: https://wg21.link/p3136r0
[P3159R0]
Bryce Adelstein Lelbach. C++ Range Adaptors and Parallel Algorithms. 18 March 2024. URL: https://wg21.link/p3159r0
[P3179R0]
Ruslan Arutyunyan, Alexey Kukanov. C++ parallel range algorithms. 15 March 2024. URL: https://wg21.link/p3179r0
[P3179R2]
Ruslan Arutyunyan, Alexey Kukanov, Bryce Adelstein Lelbach. C++ parallel range algorithms. 25 June 2024. URL: https://wg21.link/p3179r2
[P3300R0]
Bryce Adelstein Lelbach. C++ Asynchronous Parallel Algorithms. 15 February 2024. URL: https://wg21.link/p3300r0