<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html class="gr__open-std_org"><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<style type="text/css">
pre {margin-left:20pt; }
pre > i {
  font-family: "OCR A Extended", "Consolas", "Lucida Console", monospace;
  font-style:italic;
}
code > i {
  font-family: "OCR A Extended", "Consolas", "Lucida Console", monospace;
  font-style:italic;
}
pre > em {
  font-family: "OCR A Extended", "Consolas", "Lucida Console", monospace;
  font-style:italic;
}
code > em {
  font-family: "OCR A Extended", "Consolas", "Lucida Console", monospace;
  font-style:italic;
}
body { color: #000000; background-color: #FFFFFF; }
del { text-decoration: line-through; color: #8B0040; }
ins { text-decoration: underline; color: #005100; }

p.example { margin-left: 2em; }
pre.example { margin-left: 2em; }
div.example { margin-left: 2em; }

code.extract { background-color: #F5F6A2; }
pre.extract { margin-left: 2em; background-color: #F5F6A2;
  border: 1px solid #E1E28E; }

p.function { }
.attribute { margin-left: 2em; }
.attribute dt { float: left; font-style: italic;
  padding-right: 1ex; }
.attribute dd { margin-left: 0em; }

blockquote.std { color: #000000; background-color: #F1F1F1;
  border: 1px solid #D1D1D1;
  padding-left: 0.5em; padding-right: 0.5em; }
blockquote.stddel { text-decoration: line-through;
  color: #000000; background-color: #FFEBFF;
  border: 1px solid #ECD7EC;
  padding-left: 0.5empadding-right: 0.5em; ; }

blockquote.stdins { text-decoration: underline;
  color: #000000; background-color: #C8FFC8;
  border: 1px solid #B3EBB3; padding: 0.5em; }

table.header { border: 0px; border-spacing: 0;
  margin-left: 0px; font-style: normal; }

table { border: 1px solid black; border-spacing: 0px;
  margin-left: auto; margin-right: auto; }
th { text-align: left; vertical-align: top;
  padding-left: 0.4em; border: none; 
  padding-right: 0.4em; border: none; }
td { text-align: left; vertical-align: top;
  padding-left: 0.4em; border: none;
  padding-right: 0.4em; border: none; }
</style>

<title>ranges compare algorithm are over-constrained</title>
</head>

<body data-gr-c-s-loaded="true">

<table class="header"><tbody>
  <tr>
    <th>Document number:&nbsp;&nbsp;</th><th> </th><td>P1716R0</td>
  </tr>
  <tr>
    <th>Date:&nbsp;&nbsp;</th><th> </th><td>2019-06-15</td>
  </tr>
  <tr>
    <th>Audience:&nbsp;&nbsp;</th><th> </th><td>Library Evolution Working Group</td>
  </tr>
  <tr>
    <th>Reply-to:&nbsp;&nbsp;</th><th> </th><td><address>Tomasz Kamiński &lt;tomaszkam at gmail dot com&gt;</address></td>
  </tr>
</tbody></table>

<h1><a name="title"><code>ranges</code> compare algorithm are over-constrained</a></h1>

<h2><a name="intro">1. Introduction</a></h2>

<p>In this paper, we argue that the <code>ranges</code> version of the compare algorithm (like <code>equal</code>, 
   <code>mismatch</code>, <code>search</code>) are over-constrained (they impose the validity of invocations
   that are never used). Thus they compare limited functionality in comparison to their STL1 counterparts.</code>

<p>To address above issues we propose the replace the <code>IndirectRelation&lt;T, U&gt;</code> concept
   with the  <code>IndirectBinaryPredicate&lt;T, U&gt;</code>, that requires only that <code>pred(*t, *u)</code> is well-formed
   (and drop unnecessary <code>pred(*t, *t)</code>, <code>pred(*u, *t)</code> and <code>pred(*u, *u)</code> requirements).</p>

<p>Changes proposed in this paper need to be considered in the C++20 timeline, as they would constitute breaking change after the publication of standard in the current form.</p>

<!--h2><a name="toc">Table of contents</a></h2-->

<h2><a name="history">2. Revision history</a></h2>

<h3><a name="history.r0">2.1. Revision 0</a></h3>

<p>Initial revision.</p>


<h2><a name="motivation">3. Motivation and Scope</a></h2>

<p>With the current specification the <code>range</code> version of the compare algorithm (like <code>equal</code>, <code>mismatch</code>,
   <code>search</code>), are requiring that the provided functor <code>f</code> models the <code>IndirectRelation&lt;T, U&gt;</code> &mdash;
   that implies that given the pair of iterator <code>t</code> of type <code>T</code> and <code>u</code> of type <code>U</code>,
   the following expression needs to be well-formed:</p>
<ul>
  <li><code>f(*t, *t)</code>,</li>
  <li><code>f(*t, *u)</code>,</li>
  <li><code>f(*u, *t)</code>,</li>
  <li><code>f(*u, *u)</code>.</li>
</ul>
<p>[ Note: For simplicitly we ignore the projection functionality. ]</p>
<p>Out of the above only the second (<code>f(*t, *u)</code>) expression is required for the implementation of the algorithms.</p>

<p>As consequence of the above decision, the code that was working correctly with the non-range version of the algorithm:</p>
<pre>std::vector&lt;std::string&gt; texts;
std::vector&lt;std::size_T&gt; lengths;

auto [ti, si] = std::mismatch(texts.begin(), texts.end(),
                              lengths.begin(), lengths.end(),
                              [](std::string const&amp; text, std::size_t lenght) { return text.size() == lenght; });</pre>
<p>will not longer work, when migrated to <code>ranges</code> version:</p>
<pre>auto [ti, si] = std::ranges::mismatch(text, lengts, [](std::string const&amp; text, std::size_t lenght) { return text.size() == lenght; });</pre>
   
<p>The other example of the limitation of the expressiveness of the current specification is the 
   <a href="https://github.com/ericniebler/stl2/issues/599">issue reported by Eric Niebler on the github page</a>, that lead to the creation
   of this paper.</p>
<blockquote cite="https://github.com/ericniebler/stl2/issues/599">
The range-v3 calendar example has the following:
<pre>mismatch(rng-of-iterators, rng-of-sentinels, std::not_equal_to<>{})</pre>
This compiles in master but not in the deep-integration branch where mismatch is (properly) constrained with <code>IndirectRelation</code>.
</blockquote>

<p>To address the above issue we propose to replace <code>IndirectRelation</code> constrain with the <code>IndirectBinaryPredicate</code>
   (that will impose only <code>f(*t, *t)</code>) in the following algorithms:</p>
<ul>
  <li><code>find</code>,</li>
  <li><code>find_first_of</code>,</li>
  <li><code>adjacent_find</code>,</li>
  <li><code>count</code>,</li>
  <li><code>mismatch</code>,</li>
  <li><code>replace</code> and <code>replace_copy</code>,</li>
  <li><code>remove</code> and <code>remove_copy</code>.</li>
</ul>
<p>In addition we propose to change <code>IndirectlyComparable</code> to be refiment of <code>IndirectBinaryPredicate</code>
   instead of <code>IndirectRelation</code>, thus addressing:</p>
<ul>
  <li><code>split_view</code>,</li>
  <li><code>find_end</code>,</li>
  <li><code>equal</code>,</li>
  <li><code>serach</code>,</li>
  <li><code>serach_n</code>.</li>
</ul>
<p>Finally, we introduce the <code>EquivalenceRelation</code> (and <code>IndirectEquivalenceRelation</code>) to
   correctly constrain following algorithms (thier impose this requirement in non-range version):</p>
<ul>
  <li><code>unique</code> and <code>unique_copy</code>,</li>
  <li><code>is_permutation</code>.</li>
</ul>

<h3><a name="motivation.binary_predicate">3.2. <code>BinaryPredicate</code> vs <code>EquivalenceRelation</code></a></h3>

<p>Above we propose to replace <code>IndirectRelation</code> with either <code>IndirectBinaryPredicate</code> or
   <code>IndirectEquivalenceRelation</code>, depending on the algorithm.
   This may lead to the question, if we should not use <code>IndirectEquivalenceRelation</code> for each
   of the algorithms &mdash; the predicates presented in examples from the above section,
   seem to model equivalence, but only lack overloads for other argument types combinations.</p>

<p>Such approach will however silently prevent the some frequent usages of the compare algorithms like:</p>
<pre>
  // searching for first inversion in range
  auto it = std::ranges::adjacent_find(vec, std::greater{});

  auto searchPattern = [](std::string_view text, std::string_view pattern) { std::ranges::search(text, pattern); };
  // checking if all patterns can be found with in coresponding corpus
  std::ranges::equal(texts, patterns, searchPattern);
</pre>
<p>If these algorithms would be constrained with <code>IndirectEquivalenceRelation</code> the above
   code would still compile (all syntactic requirement as met as comparators are homogeneous), however,
   the code will have undefined behaviour &mdash; both <code>std::greater&lt;&gt;</code> and
   <code>serachPattern</code> does not meet the semantic requirements for equivalence relation, 
   as they are not symmetric.</p>
  

<h3><a name="motivation.overconstrained.specification">3.2. Specification requirements</a></h3>

<p>Constrains currently placed on the compare algorithms are over-constrained in context of their specification. Majority
   of the algorithms are defined to find (or just inform about existence) a pair of iterators <code>i1</code> (pointing into
   first range) and <code>i2</code> (pointing into second range), for which the following expression:</p>
<pre>invoke(pred, invoke(proj1, *i1), invoke(proj2, *i2))</pre>
<p>returns either <code>true</code> or <code>false</code> value. [ Note: Rest of them are defined in terms of other
   compare algorithms. ]</p>

<p>To illustrate: the specification of <code>serach</code> from <a href="http://eel.is/c++draft/alg.search#3">[alg.search]</a>:<p>
<blockquote class="std" cite="http://eel.is/c++draft/alg.search#3">
<pre>
template&lt;ForwardIterator I1, Sentinel&lt;I1&gt; S1, ForwardIterator I2,
         Sentinel&lt;I2&gt; S2, class Pred = ranges::equal_to,
         class Proj1 = identity, class Proj2 = identity&gt;
  requires IndirectlyComparable&lt;I1, I2, Pred, Proj1, Proj2&gt;
  constexpr subrange&lt;I1&gt;
    ranges::search(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
                   Proj1 proj1 = {}, Proj2 proj2 = {});
template&lt;ForwardRange R1, ForwardRange R2, class Pred = ranges::equal_to,
         class Proj1 = identity, class Proj2 = identity&gt;
  requires IndirectlyComparable&lt;iterator_t&lt;R1&gt;, iterator_t&lt;R2&gt;, Pred, Proj1, Proj2&gt;
  constexpr safe_subrange_t&lt;R1&gt;
    ranges::search(R1&amp;&amp; r1, R2&amp;&amp; r2, Pred pred = {},
                   Proj1 proj1 = {}, Proj2 proj2 = {});
</pre>
  <dl class="attribute">

    <dt>Returns:</dt> 
    <dd><p>&nbsp;</p>
     <ul>
       <li><code>{i, i + (last2 - first2)}</code>, where <code>i</code> is the first iterator in the range <code>[first1, last1 - (last2 - first2))</code>
          such that for every non-negative integer <code>n</code> less than <code>last2 - first2</code> the condition
          <pre>bool(invoke(pred, invoke(proj1, *(i + n)), invoke(proj2, *(first2 + n))))</pre>
          is true</li>
       <li>Returns <code>{last1, last1}</code> if no such iterator exists.</li>
     </ul>
   <p></p></dd>

   <dt>Complexity:</dt>
   <dd><p>At most <code>(last1 - first1) * (last2 - first2)</code> applications of the corresponding predicate and projections.</p></dd>

  </dl>
</blockquote>

<p>To implement above specification only the invocation of <code>f(proj1(*i1), proj2(*i2))</code> is required,
   and any other combinations of argument (like <code>f(proj(*i1), proj1(*i1))</code>) is unnecessary.</p>


<h3><a name="motivation.overconstrained.stl1">3.3. Non-range specification</a></h3>

<p>The old non-range algorithms are constrained using the <code>BinaryPredicate</code> requirements, that was implied
   by the template parameter. Per <a href="http://eel.is/c++draft/algorithms.requirements#8">[algorithms.requirements]</a>,
   this only requires the predicate to be invocable with iterators provided in order of their occurrence in range
   signature:</p>

<blockquote class="std" cite="http://eel.is/c++draft/algorithms.requirements#8">
   <dl class="attribute">
     <dd><p>
       When not otherwise constrained, the <code>BinaryPredicate</code> parameter is used whenever an algorithm expects a function object that when applied
       to the result of dereferencing two corresponding iterators or to dereferencing an iterator and type <code>T</code> when <code>T</code> is part of the signature returns a value testable as <code>true</code>.
       In other words, if an algorithm takes <code>BinaryPredicate</code> <code>binary_pred</code> as its argument and <code>first1</code> and <code>first2</code> as its iterator arguments 
       with respective value types <code>T1</code> and <code>T2</code>, it should work correctly in the construct <code>binary_pred(*first1, *first2)</code> contextually converted to <code>bool</code> ([conv]).
     </p></dd>
</blockquote>
<p>[ Note: <code>is_permutation</code>, <code>unique</code> and <code>unique_copy</code> imposes additional requirement
     on predicate: it should impose equivalence relation on the arguments. ]</p>

<p>Due above, the non-range versions of the algorithms are more general and applicable, than their <code>ranges</code>
   counterpart. In addition, this unnecessary complicate the migration of the code to the rangified version of STL.</p>

<h2><a name="wording">4. Proposed Wording</a></h2>

<p>The proposed wording changes refer to <a href="http://wg21.link/n4810"></a> N4810 (C++ Working Draft, 2019-03-15).</p>

<p>Apply following changes to [concepts.syn] Header <code>&lt;concepts&gt;</code> synopsis:</p>
<blockquote class="std">
<pre>
// [concept.relation], concept Relation
template&lt;class R, class T, class U&gt;
  concept Relation = &lt;em&gt;see below&lt;/em&gt;;

<ins>
// [concept.equivalencerelation], concept EquivalenceRelation
template&lt;class R, class T, class U&gt;
  concept EquivalenceRelation = &lt;em&gt;see below&lt;/em&gt;;
</ins>

// [concept.strictweakorder], concept StrictWeakOrder
template&lt;class R, class T, class U&gt;
  concept StrictWeakOrder = &lt;em&gt;see below&lt;/em&gt;;
</pre>
</blockquote>

<p>Insert following section after [oncept.relation] Concept <code>EquivalenceRelation</code>:</p>
<blockquote class="stdins"> 
<h4><a name="concept.equivalencerelation">Concept <code>EquivalenceRelation</code> <span style="float:right">[concept.equivalencerelation]</span></a></h4>

<pre>
template&lt;class R, class T, class U&gt;
  concept EquivalenceRelation = Relation&lt;R, T, U&gt;;
</pre>

  <dl class="attribute">
    <dd>A <code>Relation</code> satisfies <code>EquivalenceRelation</code> only if it imposes an equivalence relation on its arguments.</dd>
  </dl>
</blockquote>


<p>Apply following changes to section [iterator.synopsis] Header <code>&lt;iterator&gt;</code> synopsis:</p>
<blockquote class="std">
<pre>
template&lt;class F, class I1, class I2<del> = I1</del>&gt;
  concept Indirect<ins>BinaryPredicate</ins><del>Relation</del> = <em>see below</em>;

<ins>template&lt;class F, class I1, class I2i = I1&gt;
  concept IndirectEquivalenceRelation = <em>see below</em>;</ins>

template&lt;class F, class I1, class I2 = I1&gt;
  concept IndirectStrictWeakOrder = <em>see below</em>;

</pre>
</blockquote>


<p>Apply following changes to section [indirectcallable.indirectinvocable] Indirect callables:</p>
<blockquote class="std">
<pre>
template&lt;class F, class I1, class I2<del> = I1</del>&gt;
  concept Indirect<ins>BinaryPredicate</ins><del>Relation</del> =
    Readable&lt;I1&gt; &amp;&amp; Readable&lt;I2&gt; &amp;&amp;
    CopyConstructible&lt;F&gt; &amp;&amp;
    <ins>Predicate</ins><del>Relation</del>&lt;F&amp;, iter_value_t&lt;I1&gt;&amp;, iter_value_t&lt;I2&gt;&amp;&gt; &amp;&amp;
    <ins>Predicate</ins><del>Relation</del>&lt;F&amp;, iter_value_t&lt;I1&gt;&amp;, iter_reference_t&lt;I2&gt;&gt; &amp;&amp;
    <ins>Predicate</ins><del>Relation</del>&lt;F&amp;, iter_reference_t&lt;I1&gt;, iter_value_t&lt;I2&gt;&amp;&gt; &amp;&amp;
    <ins>Predicate</ins><del>Relation</del>&lt;F&amp;, iter_reference_t&lt;I1&gt;, iter_reference_t&lt;I2&gt;&gt; &amp;&amp;
    <ins>Predicate</ins><del>Relation</del>&lt;F&amp;, iter_common_reference_t&lt;I1&gt;, iter_common_reference_t&lt;I2&gt;&gt;;

<ins>template&lt;class F, class I1, class I2 = I1&gt;
  concept IndirectEquivalenceRelation =
    Readable&lt;I1&gt; &amp;&amp; Readable&lt;I2&gt; &amp;&amp;
    CopyConstructible&lt;F&gt; &amp;&amp;
    EquivalenceRelation&lt;F&amp;, iter_value_t&lt;I1&gt;&amp;, iter_value_t&lt;I2&gt;&amp;&gt; &amp;&amp;
    EquivalenceRelation&lt;F&amp;, iter_value_t&lt;I1&gt;&amp;, iter_reference_t&lt;I2&gt;&gt; &amp;&amp;
    EquivalenceRelation&lt;F&amp;, iter_reference_t&lt;I1&gt;, iter_value_t&lt;I2&gt;&amp;&gt; &amp;&amp;
    EquivalenceRelation&lt;F&amp;, iter_reference_t&lt;I1&gt;, iter_reference_t&lt;I2&gt;&gt; &amp;&amp;
    EquivalenceRelation&lt;F&amp;, iter_common_reference_t&lt;I1&gt;, iter_common_reference_t&lt;I2&gt;&gt;;</ins>

template&lt;class F, class I1, class I2 = I1&gt;
  concept IndirectStrictWeakOrder =
    Readable&lt;I1&gt; &amp;&amp; Readable&lt;I2&gt; &amp;&amp;
    CopyConstructible&lt;F&gt; &amp;&amp;
    StrictWeakOrder&lt;F&amp;, iter_value_t&lt;I1&gt;&amp;, iter_value_t&lt;I2&gt;&amp;&gt; &amp;&amp;
    StrictWeakOrder&lt;F&amp;, iter_value_t&lt;I1&gt;&amp;, iter_reference_t&lt;I2&gt;&gt; &amp;&amp;
    StrictWeakOrder&lt;F&amp;, iter_reference_t&lt;I1&gt;, iter_value_t&lt;I2&gt;&amp;&gt; &amp;&amp;
    StrictWeakOrder&lt;F&amp;, iter_reference_t&lt;I1&gt;, iter_reference_t&lt;I2&gt;&gt; &amp;&amp;
    StrictWeakOrder&lt;F&amp;, iter_common_reference_t&lt;I1&gt;, iter_common_reference_t&lt;I2&gt;&gt;;
</pre>
</blockquote>

<p>Apply following changes to section [alg.req.ind.cmp] Concept <code>IndirectlyComparable</code>:</p>
<blockquote class="std">
<pre>
template&lt;class I1, class I2, class R, class P1 = identity, 
        class P2 = identity&gt;
   concept IndirectlyComparable 
      = Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;R, projected&lt;I1, P1&gt;, projected&lt;I2, P2&gt;&gt;;
</pre>
</blockquote>


<p>Apply following changes to section [algorithm.syn] Header <code>&lt;algorithm&gt;</code> synopsis:</p>
<blockquote class="std">
<pre>
namespace ranges {

template&lt;InputIterator I, Sentinel&lt;I&gt; S, class T, class Proj = identity&gt;
  requires Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;I, Proj&gt;, const T*&gt;
  constexpr I find(I first, S last, const T&amp; value, Proj proj = {});

template&lt;InputRange R, class T, class Proj = identity&gt;
  requires Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;iterator_t&lt;R&gt;, Proj&gt;, const T*&gt;
  constexpr safe_iterator_t&lt;R&gt;
     find(R&amp;&amp; r, const T&amp; value, Proj proj = {});

template&lt;InputIterator I, Sentinel&lt;I&gt; S, class Proj = identity,
         IndirectUnaryPredicate&lt;projected&lt;I, Proj&gt;&gt; Pred&gt;
constexpr I find_if(I first, S last, Pred pred, Proj proj = {});

template&lt;InputRange R, class Proj = identity,
         IndirectUnaryPredicate&lt;projected&lt;iterator_t&lt;R&gt;, Proj&gt;&gt; Pred&gt;
constexpr safe_iterator_t&lt;R&gt;
  find_if(R&amp;&amp; r, Pred pred, Proj proj = {});

template&lt;InputIterator I, Sentinel&lt;I&gt; S, class Proj = identity,
         IndirectUnaryPredicate&lt;projected&lt;I, Proj&gt;&gt; Pred&gt;
constexpr I find_if_not(I first, S last, Pred pred, Proj proj = {});

template&lt;InputRange R, class Proj = identity,
         IndirectUnaryPredicate&lt;projected&lt;iterator_t&lt;R&gt;, Proj&gt;&gt; Pred&gt;
constexpr safe_iterator_t&lt;R&gt;find_if_not(R&amp;&amp; r, Pred pred, Proj proj = {});

}

[...]

namespace ranges {

template&lt;InputIterator I1, Sentinel&lt;I1&gt; S1, ForwardIterator I2, Sentinel&lt;I2&gt; S2,
         <ins>class Pred = ranges::equal_to,</ins> class Proj1 = identity, class Proj2 = identity,
         <del>IndirectRelation&lt;projected&lt;I1, Proj1&gt;,</del>
                          <del>projected&lt;I2, Proj2&gt;&gt; Pred = ranges::equal_to</del>&gt;
  <ins>requires IndirectlyComparable&lt;I1, I2, Pred, Proj1, Proj2&gt;</ins>
  constexpr I1 find_first_of(I1 first1, S1 last1, I2 first2, S2 last2,
                             Pred pred = {},
                             Proj1 proj1 = {}, Proj2 proj2 = {});

template&lt;InputRange R1, ForwardRange R2, <ins>class Pred = ranges::equal_to,</ins> class Proj1 = identity, class Proj2 = identity,
        <del>IndirectRelation&lt;projected&lt;iterator_t&lt;R1&gt;, Proj1&gt;,</del>
                         <del>projected&lt;iterator_t&lt;R2&gt;, Proj2&gt;&gt; Pred = ranges::equal_to</del>&gt;
  <ins>requires IndirectlyComparable&lt;iterator_t&lt;R1&gt;, iterator_t&lt;R2&gt;, Pred, Proj1, Proj2&gt;</ins>
  constexpr safe_iterator_t&lt;R1&gt;
    find_first_of(R1&amp;&amp; r1, R2&amp;&amp; r2,
                  Pred pred = {},
                  Proj1 proj1 = {}, Proj2 proj2 = {});

}

[...]

namespace ranges {

template&lt;ForwardIterator I, Sentinel&lt;I&gt; S, class Proj = identity,
         Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;projected&lt;I, Proj&gt;<ins>, projected&lt;I, Proj&gt;</ins>&gt; Pred = ranges::equal_to&gt;
  constexpr I adjacent_find(I first, S last, Pred pred = {},
                            Proj proj = {});

template&lt;ForwardRange R, class Proj = identity,
         Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;projected&lt;iterator_t&lt;R&gt;, Proj&gt;<ins>, projected&lt;iterator_t&lt;R&gt;, Proj&gt;</ins>&gt; Pred = ranges::equal_to&gt;
  constexpr safe_iterator_t&lt;R&gt;
    adjacent_find(R&amp;&amp; r, Pred pred = {}, Proj proj = {});

}

[...]

namespace ranges {

template&lt;InputIterator I, Sentinel&lt;I&gt; S, class T, class Proj = identity&gt;
  requires Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;I, Proj&gt;, const T*&gt;
  constexpr iter_difference_t&lt;I&gt;
    count(I first, S last, const T&amp; value, Proj proj = {});

template&lt;InputRange R, class T, class Proj = identity&gt;
  requires Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;iterator_t&lt;R&gt;, Proj&gt;, const T*&gt;
  constexpr iter_difference_t&lt;iterator_t&lt;R&gt;&gt;
    count(R&amp;&amp; r, const T&amp; value, Proj proj = {});

template&lt;InputIterator I, Sentinel&lt;I&gt; S, class Proj = identity,
         IndirectUnaryPredicate&lt;projected&lt;I, Proj&gt;&gt; Pred&gt;
  constexpr iter_difference_t&lt;I&gt;
    count_if(I first, S last, Pred pred, Proj proj = {});

template&lt;InputRange R, class Proj = identity,
         IndirectUnaryPredicate&lt;projected&lt;iterator_t&lt;R&gt;, Proj&gt;&gt; Pred&gt;
  constexpr iter_difference_t&lt;iterator_t&lt;R&gt;&gt;
    count_if(R&amp;&amp; r, Pred pred, Proj proj = {});

}

[...]

namespace ranges {

[...]

template&lt;InputIterator I1, Sentinel&lt;I1&gt; S1, InputIterator I2, Sentinel&lt;I2&gt; S2,
         <ins>class Pred = ranges::equal_to,</ins> class Proj1 = identity, class Proj2 = identity,
         <del>IndirectRelation&lt;projected&lt;I1, Proj1&gt;,</del>
                          <del>projected&lt;I2, Proj2&gt;&gt; Pred = ranges::equal_to</del>&gt;
  <ins>requires IndirectlyComparable&lt;I1, I2, Pred, Proj1, Proj2&gt;</ins>
  constexpr mismatch_result&lt;I1, I2&gt;
    mismatch(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
             Proj1 proj1 = {}, Proj2 proj2 = {});


template&lt;InputRange R1, InputRange R2,
         <ins>class Pred = ranges::equal_to,</ins> class Proj1 = identity, class Proj2 = identity,
         <del>IndirectRelation&lt;projected&lt;iterator_t&lt;R1&gt;, Proj1&gt;,</del>
                          <del>projected&lt;iterator_t&lt;R2&gt;, Proj2&gt;&gt; Pred = ranges::equal_to</del>&gt;
  <ins>requires IndirectlyComparable&lt;iterator_t&lt;R1&gt;, iterator_t&lt;R2&gt;, Pred, Proj1, Proj2&gt;</ins>
  constexpr mismatch_result&lt;safe_iterator_t&lt;R1&gt;, safe_iterator_t&lt;R2&gt;&gt;
    mismatch(R1&amp;&amp; r1, R2&amp;&amp; r2, Pred pred = {},i
             Proj1 proj1 = {}, Proj2 proj2 = {});

}

[...]

namespace ranges {

template&lt;ForwardIterator I1, Sentinel&lt;I1&gt; S1, ForwardIterator I2,
         Sentinel&lt;I2&gt; S2, <del>class Pred = ranges::equal_to,</del> class Proj1 = identity, class Proj2 = identity&gt;<ins>,</ins>
         <ins>IndirectEquivalenceRelation&lt;projected&lt;I1, Proj1&gt;, projected&lt;I2, Proj2&gt;&gt; Pred = ranges::equal_to</ins>&gt;
  <del>requires IndirectlyComparable&lt;I1, I2, Pred, Proj1, Proj2&gt;</del>
  constexpr bool is_permutation(I1 first1, S1 last1, I2 first2, S2 last2,
                                Pred pred = {},
                                Proj1 proj1 = {}, Proj2 proj2 = {});

template&lt;ForwardRange R1, ForwardRange R2, <del>class Pred = ranges::equal_to,</del>
         class Proj1 = identity, class Proj2 = identity<ins>,</ins>
         <ins>IndirectEquivalenceRelation&lt;projected&lt;iterator_t&lt;R1&gt;, Proj1&gt;, projected&lt;iterator_t&lt;R2&gt;, Proj2&gt;&gt; Pred = ranges::equal_to</ins>&gt;
  <del>requires IndirectlyComparable&lt;iterator_t&lt;R1&gt;, iterator_t&lt;R2&gt;, Pred, Proj1, Proj2&gt;</del>
  constexpr bool is_permutation(R1&amp;&amp; r1, R2&amp;&amp; r2, Pred pred = {},
                                Proj1 proj1 = {}, Proj2 proj2 = {});

}

[...]

namespace ranges {

template&lt;InputIterator I, Sentinel&lt;I&gt; S, class T1, class T2, class Proj = identity&gt;
  requires Writable&lt;I, const T2&amp;&gt; &amp;&amp;
           Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;I, Proj&gt;, const T1*&gt;
  constexpr I
    replace(I first, S last, const T1&amp; old_value, const T2&amp; new_value, Proj proj = {});

template&lt;InputRange R, class T1, class T2, class Proj = identity&gt;
  requires Writable&lt;iterator_t&lt;R&gt;, const T2&amp;&gt; &amp;&amp;
    Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;iterator_t&lt;R&gt;, Proj&gt;, const T1*&gt;
constexpr safe_iterator_t&lt;R&gt;
  replace(R&amp;&amp; r, const T1&amp; old_value, const T2&amp; new_value, Proj proj = {});

template&lt;InputIterator I, Sentinel&lt;I&gt; S, class T, class Proj = identity,
         IndirectUnaryPredicate&lt;projected&lt;I, Proj&gt;&gt; Pred&gt;
  requires Writable&lt;I, const T&amp;&gt;
  constexpr I replace_if(I first, S last, Pred pred, const T&amp; new_value, Proj proj = {});

template&lt;InputRange R, class T, class Proj = identity,
         IndirectUnaryPredicate&lt;projected&lt;iterator_t&lt;R&gt;, Proj&gt;&gt; Pred&gt;
requires Writable&lt;iterator_t&lt;R&gt;, const T&amp;&gt;
  constexpr safe_iterator_t&lt;R&gt;replace_if(R&amp;&amp; r, Pred pred, const T&amp; new_value, Proj proj = {});

}

[...]

namespace ranges {

template&lt;class I, class O&gt;
using replace_copy_result = copy_result&lt;I, O&gt;;

template&lt;InputIterator I, Sentinel&lt;I&gt; S, class T1, class T2, OutputIterator&lt;const T2&amp;&gt; O,
         class Proj = identity&gt;
  requires IndirectlyCopyable&lt;I, O&gt; &amp;&amp;
           Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;I, Proj&gt;, const T1*&gt;
constexpr replace_copy_result&lt;I, O&gt;
  replace_copy(I first, S last, O result, const T1&amp; old_value, const T2&amp; new_value,
               Proj proj = {});

template&lt;InputRange R, class T1, class T2, OutputIterator&lt;const T2&amp;&gt; O,
         class Proj = identity&gt;
  requires IndirectlyCopyable&lt;iterator_t&lt;R&gt;, O&gt; &amp;&amp;
           Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;iterator_t&lt;R&gt;, Proj&gt;, const T1*&gt;
  constexpr replace_copy_result&lt;safe_iterator_t&lt;R&gt;, O&gt;
    replace_copy(R&amp;&amp; r, O result, const T1&amp; old_value, const T2&amp; new_value,
                 Proj proj = {});

template&lt;class I, class O&gt;
  using replace_copy_if_result = copy_result&lt;I, O&gt;;

template&lt;InputIterator I, Sentinel&lt;I&gt; S, class T, OutputIterator&lt;const T&amp;&gt; O,
          class Proj = identity, IndirectUnaryPredicate&lt;projected&lt;I, Proj&gt;&gt; Pred&gt;
  requires IndirectlyCopyable&lt;I, O&gt;
  constexpr replace_copy_if_result&lt;I, O&gt;
    replace_copy_if(I first, S last, O result, Pred pred, const T&amp; new_value,
                    Proj proj = {});

template&lt;InputRange R, class T, OutputIterator&lt;const T&amp;&gt; O, class Proj = identity,
         IndirectUnaryPredicate&lt;projected&lt;iterator_t&lt;R&gt;, Proj&gt;&gt; Pred&gt;
  requires IndirectlyCopyable&lt;iterator_t&lt;R&gt;, O&gt;
  constexpr replace_copy_if_result&lt;safe_iterator_t&lt;R&gt;, O&gt;
    replace_copy_if(R&amp;&amp; r, O result, Pred pred, const T&amp; new_value,
                    Proj proj = {});

}

[...]

namespace ranges {

template&lt;Permutable I, Sentinel&lt;I&gt; S, class T, class Proj = identity&gt;
  requires Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;I, Proj&gt;, const T*&gt;
  constexpr I remove(I first, S last, const T&amp; value, Proj proj = {});

template&lt;ForwardRange R, class T, class Proj = identity&gt;
  requires Permutable&lt;iterator_t&lt;R&gt;&gt; &amp;&amp;
           Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;iterator_t&lt;R&gt;, Proj&gt;, const T*&gt;
constexpr safe_iterator_t&lt;R&gt;
  remove(R&amp;&amp; r, const T&amp; value, Proj proj = {});

template&lt;Permutable I, Sentinel&lt;I&gt; S, class Proj = identity,
  IndirectUnaryPredicate&lt;projected&lt;I, Proj&gt;&gt; Pred&gt;
  constexpr I remove_if(I first, S last, Pred pred, Proj proj = {});

template&lt;ForwardRange R, class Proj = identity,
         IndirectUnaryPredicate&lt;projected&lt;iterator_t&lt;R&gt;, Proj&gt;&gt; Pred&gt;
  requires Permutable&lt;iterator_t&lt;R&gt;&gt;
  constexpr safe_iterator_t&lt;R&gt;
    remove_if(R&amp;&amp; r, Pred pred, Proj proj = {});

}

[...]

namespace ranges {

template&lt;class I, class O&gt;
using remove_copy_result = copy_result&lt;I, O&gt;;

template&lt;InputIterator I, Sentinel&lt;I&gt; S, WeaklyIncrementable O, class T,
         class Proj = identity&gt;
  requires IndirectlyCopyable&lt;I, O&gt; &amp;&amp;
           Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;I, Proj&gt;, const T*&gt;
  constexpr remove_copy_result&lt;I, O&gt;
    remove_copy(I first, S last, O result, const T&amp; value, Proj proj = {});

template&lt;InputRange R, WeaklyIncrementable O, class T, class Proj = identity&gt;
  requires IndirectlyCopyable&lt;iterator_t&lt;R&gt;, O&gt; &amp;&amp;
           Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;iterator_t&lt;R&gt;, Proj&gt;, const T*&gt;
  constexpr remove_copy_result&lt;safe_iterator_t&lt;R&gt;, O&gt;
    remove_copy(R&amp;&amp; r, O result, const T&amp; value, Proj proj = {});

template&lt;class I, class O&gt;
  using remove_copy_if_result = copy_result&lt;I, O&gt;;

template&lt;InputIterator I, Sentinel&lt;I&gt; S, WeaklyIncrementable O,
         class Proj = identity, IndirectUnaryPredicate&lt;projected&lt;I, Proj&gt;&gt; Pred&gt;
  requires IndirectlyCopyable&lt;I, O&gt;
  constexpr remove_copy_if_result&lt;I, O&gt;
    remove_copy_if(I first, S last, O result, Pred pred, Proj proj = {});

template&lt;InputRange R, WeaklyIncrementable O, class Proj = identity,
         IndirectUnaryPredicate&lt;projected&lt;iterator_t&lt;R&gt;, Proj&gt;&gt; Pred&gt;
  requires IndirectlyCopyable&lt;iterator_t&lt;R&gt;, O&gt;
  constexpr remove_copy_if_result&lt;safe_iterator_t&lt;R&gt;, O&gt;
    remove_copy_if(R&amp;&amp; r, O result, Pred pred, Proj proj = {});

}

[...]

namespace ranges {

template&lt;Permutable I, Sentinel&lt;I&gt; S, class Proj = identity,
  Indirect<ins>Equivalence</ins>Relation&lt;projected&lt;I, Proj&gt;&gt; C = ranges::equal_to&gt;
  constexpr I unique(I first, S last, C comp = {}, Proj proj = {});

template&lt;ForwardRange R, class Proj = identity,
         Indirect<ins>Equivalence</ins>Relation&lt;projected&lt;iterator_t&lt;R&gt;, Proj&gt;&gt; C = ranges::equal_to&gt;
  requires Permutable&lt;iterator_t&lt;R&gt;&gt;
  constexpr safe_iterator_t&lt;R&gt;
    unique(R&amp;&amp; r, C comp = {}, Proj proj = {});

}

[...]

namespace ranges {

template&lt;class I, class O&gt;
using unique_copy_result = copy_result&lt;I, O&gt;;

template&lt;InputIterator I, Sentinel&lt;I&gt; S, WeaklyIncrementable O,
         class Proj = identity, Indirect<ins>Equivalence</ins>Relation&lt;projected&lt;I, Proj&gt;&gt; C = ranges::equal_to&gt;
  requires IndirectlyCopyable&lt;I, O&gt; &amp;&amp;
           (ForwardIterator&lt;I&gt; ||
            (InputIterator&lt;O&gt; &amp;&amp; Same&lt;iter_value_t&lt;I&gt;, iter_value_t&lt;O&gt;&gt;) ||
            IndirectlyCopyableStorable&lt;I, O&gt;)
  constexpr unique_copy_result&lt;I, O&gt;
    unique_copy(I first, S last, O result, C comp = {}, Proj proj = {});

template&lt;InputRange R, WeaklyIncrementable O, class Proj = identity,
         Indirect<ins>Equivalence</ins>Relation&lt;projected&lt;iterator_t&lt;R&gt;, Proj&gt;&gt; C = ranges::equal_to&gt;
  requires IndirectlyCopyable&lt;iterator_t&lt;R&gt;, O&gt; &amp;&amp;
          (ForwardIterator&lt;iterator_t&lt;R&gt;&gt; ||
           (InputIterator&lt;O&gt; &amp;&amp; Same&lt;iter_value_t&lt;iterator_t&lt;R&gt;&gt;, iter_value_t&lt;O&gt;&gt;) ||
            IndirectlyCopyableStorable&lt;iterator_t&lt;R&gt;, O&gt;)
  constexpr unique_copy_result&lt;safe_iterator_t&lt;R&gt;, O&gt;
    unique_copy(R&amp;&amp; r, O result, C comp = {}, Proj proj = {});

}
</pre>
</blockquote>

<p>Apply following changes to section [alg.find] Find:</p>
<blockquote class="std">
<pre>
template&lt;InputIterator I, Sentinel&lt;I&gt; S, class T, class Proj = identity&gt;
  requires Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;I, Proj&gt;, const T*&gt;
  constexpr I ranges::find(I first, S last, const T&amp; value, Proj proj = {});

template&lt;InputRange R, class T, class Proj = identity&gt;
  requires Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;iterator_t&lt;R&gt;, Proj&gt;, const T*&gt;
  constexpr safe_iterator_t&lt;R&gt;
     ranges::find(R&amp;&amp; r, const T&amp; value, Proj proj = {});
</pre>
</blockquote>

<p>Apply following changes to section [alg.find.first.of] Find first:</p>
<blockquote class="std">
<pre>
template&lt;InputIterator I1, Sentinel&lt;I1&gt; S1, ForwardIterator I2, Sentinel&lt;I2&gt; S2,
         <ins>class Pred = ranges::equal_to,</ins> class Proj1 = identity, class Proj2 = identity,
         <del>IndirectRelation&lt;projected&lt;I1, Proj1&gt;,</del>
                          <del>projected&lt;I2, Proj2&gt;&gt; Pred = ranges::equal_to</del>&gt;
  <ins>requires IndirectlyComparable&lt;I1, I2, Pred, Proj1, Proj2&gt;</ins>
  constexpr I1 ranges::find_first_of(I1 first1, S1 last1, I2 first2, S2 last2,
                                     Pred pred = {},
                                     Proj1 proj1 = {}, Proj2 proj2 = {});

template&lt;InputRange R1, ForwardRange R2, <ins>class Pred = ranges::equal_to,</ins> class Proj1 = identity, class Proj2 = identity,
        <del>IndirectRelation&lt;projected&lt;iterator_t&lt;R1&gt;, Proj1&gt;,</del>
                         <del>projected&lt;iterator_t&lt;R2&gt;, Proj2&gt;&gt; Pred = ranges::equal_to</del>&gt;
  <ins>requires IndirectlyComparable&lt;iterator_t&lt;R1&gt;, iterator_t&lt;R2&gt;, Pred, Proj1, Proj2&gt;</ins>
  constexpr safe_iterator_t&lt;R1&gt;
    ranges::find_first_of(R1&amp;&amp; r1, R2&amp;&amp; r2,
                          Pred pred = {},
                          Proj1 proj1 = {}, Proj2 proj2 = {});

</pre>
</blockquote>


<p>Apply following changes to section [alg.adjacent.find] Adjacent find:</p>
<blockquote class="std">
<pre>
template&lt;ForwardIterator I, Sentinel&lt;I&gt; S, class Proj = identity,
         Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;projected&lt;I, Proj&gt;<ins>, projected&lt;I, Proj&gt;</ins>&gt; Pred = ranges::equal_to&gt;
  constexpr I ranges::adjacent_find(I first, S last, Pred pred = {},
                                    Proj proj = {});

template&lt;ForwardRange R, class Proj = identity,
         Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;projected&lt;iterator_t&lt;R&gt;, Proj&gt;<ins>, projected&lt;iterator_t&lt;R&gt;, Proj&gt;</ins>&gt; Pred = ranges::equal_to&gt;
  constexpr safe_iterator_t&lt;R&gt;
    ranges::adjacent_find(R&amp;&amp; r, Pred pred = {}, Proj proj = {});

</pre>
</blockquote>

<p>Apply following changes to section [alg.is.permutation] Is permutation:</p>
<blockquote class="std">
<pre>
template&lt;ForwardIterator I1, Sentinel&lt;I1&gt; S1, ForwardIterator I2,
         Sentinel&lt;I2&gt; S2, <del>class Pred = ranges::equal_to,</del> class Proj1 = identity, class Proj2 = identity&gt;<ins>,</ins>
         <ins>IndirectEquivalenceRelation&lt;projected&lt;I1, Proj1&gt;, projected&lt;I2, Proj2&gt;&gt; Pred = ranges::equal_to</ins>&gt;
  <del>requires IndirectlyComparable&lt;I1, I2, Pred, Proj1, Proj2&gt;</del>
  constexpr bool ranges::is_permutation(I1 first1, S1 last1, I2 first2, S2 last2,
                                        Pred pred = {},
                                        Proj1 proj1 = {}, Proj2 proj2 = {});

template&lt;ForwardRange R1, ForwardRange R2, <del>class Pred = ranges::equal_to,</del>
         class Proj1 = identity, class Proj2 = identity<ins>,</ins>
         <ins>IndirectEquivalenceRelation&lt;projected&lt;iterator_t&lt;R1&gt;, Proj1&gt;, projected&lt;iterator_t&lt;R2&gt;, Proj2&gt;&gt; Pred = ranges::equal_to</ins>&gt;
  <del>requires IndirectlyComparable&lt;iterator_t&lt;R1&gt;, iterator_t&lt;R2&gt;, Pred, Proj1, Proj2&gt;</del>
  constexpr bool ranges::is_permutation(R1&amp;&amp; r1, R2&amp;&amp; r2, Pred pred = {},
                                        Proj1 proj1 = {}, Proj2 proj2 = {});

</pre>
</blockquote>

<p>Apply following changes to section [alg.count] Count:</p>
<blockquote class="std">
<pre>
template&lt;InputIterator I, Sentinel&lt;I&gt; S, class T, class Proj = identity&gt;
  requires Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;I, Proj&gt;, const T*&gt;
  constexpr iter_difference_t&lt;I&gt;
    ranges::count(I first, S last, const T&amp; value, Proj proj = {});

template&lt;InputRange R, class T, class Proj = identity&gt;
  requires Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;iterator_t&lt;R&gt;, Proj&gt;, const T*&gt;
  constexpr iter_difference_t&lt;iterator_t&lt;R&gt;&gt;
    ranges::count(R&amp;&amp; r, const T&amp; value, Proj proj = {});
</pre>
</blockquote>

<p>Apply following changes to section [alg.mismatch] Mismatch:</p>
<blockquote class="std">
<pre>
template&lt;InputIterator I1, Sentinel&lt;I1&gt; S1, InputIterator I2, Sentinel&lt;I2&gt; S2,
         <ins>class Pred = ranges::equal_to,</ins> class Proj1 = identity, class Proj2 = identity,
         <del>IndirectRelation&lt;projected&lt;I1, Proj1&gt;,</del>
                          <del>projected&lt;I2, Proj2&gt;&gt; Pred = ranges::equal_to</del>&gt;
  <ins>requires IndirectlyComparable&lt;I1, I2, Pred, Proj1, Proj2&gt;</ins>
  constexpr mismatch_result&lt;I1, I2&gt;
    ranges::mismatch(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
                     Proj1 proj1 = {}, Proj2 proj2 = {});


template&lt;InputRange R1, InputRange R2,
         <ins>class Pred = ranges::equal_to,</ins> class Proj1 = identity, class Proj2 = identity,
         <del>IndirectRelation&lt;projected&lt;iterator_t&lt;R1&gt;, Proj1&gt;,</del>
                          <del>projected&lt;iterator_t&lt;R2&gt;, Proj2&gt;&gt; Pred = ranges::equal_to</del>&gt;
  <ins>requires IndirectlyComparable&lt;iterator_t&lt;R1&gt;, iterator_t&lt;R2&gt;, Pred, Proj1, Proj2&gt;</ins>
  constexpr mismatch_result&lt;safe_iterator_t&lt;R1&gt;, safe_iterator_t&lt;R2&gt;&gt;
    ranges::mismatch(R1&amp;&amp; r1, R2&amp;&amp; r2, Pred pred = {},i
                     Proj1 proj1 = {}, Proj2 proj2 = {});
</pre>
</blockquote>

<p>Apply following changes to section [alg.replace] Replace:</p>
<blockquote class="std">
<pre>
template&lt;InputIterator I, Sentinel&lt;I&gt; S, class T1, class T2, class Proj = identity&gt;
  requires Writable&lt;I, const T2&amp;&gt; &amp;&amp;
           Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;I, Proj&gt;, const T1*&gt;
  constexpr I
    ranges::replace(I first, S last, const T1&amp; old_value, const T2&amp; new_value, Proj proj = {});

template&lt;InputRange R, class T1, class T2, class Proj = identity&gt;
  requires Writable&lt;iterator_t&lt;R&gt;, const T2&amp;&gt; &amp;&amp;
    Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;iterator_t&lt;R&gt;, Proj&gt;, const T1*&gt;
constexpr safe_iterator_t&lt;R&gt;
  ranges::replace(R&amp;&amp; r, const T1&amp; old_value, const T2&amp; new_value, Proj proj = {});

[...]

template&lt;InputIterator I, Sentinel&lt;I&gt; S, class T1, class T2, OutputIterator&lt;const T2&amp;&gt; O,
         class Proj = identity&gt;
  requires IndirectlyCopyable&lt;I, O&gt; &amp;&amp;
           Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;I, Proj&gt;, const T1*&gt;
constexpr replace_copy_result&lt;I, O&gt;
  ranges::replace_copy(I first, S last, O result, const T1&amp; old_value, const T2&amp; new_value,
                       Proj proj = {});

template&lt;InputRange R, class T1, class T2, OutputIterator&lt;const T2&amp;&gt; O,
         class Proj = identity&gt;
  requires IndirectlyCopyable&lt;iterator_t&lt;R&gt;, O&gt; &amp;&amp;
           Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;iterator_t&lt;R&gt;, Proj&gt;, const T1*&gt;
  constexpr replace_copy_result&lt;safe_iterator_t&lt;R&gt;, O&gt;
    ranges::replace_copy(R&amp;&amp; r, O result, const T1&amp; old_value, const T2&amp; new_value,
                         Proj proj = {});
</pre>
</blockquote>

<p>Apply following changes to section [alg.remove] Remove:</p>
<blockquote class="std">
<pre>
template&lt;Permutable I, Sentinel&lt;I&gt; S, class T, class Proj = identity&gt;
  requires Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;I, Proj&gt;, const T*&gt;
  constexpr I ranges::remove(I first, S last, const T&amp; value, Proj proj = {});

template&lt;ForwardRange R, class T, class Proj = identity&gt;
  requires Permutable&lt;iterator_t&lt;R&gt;&gt; &amp;&amp;
           Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;iterator_t&lt;R&gt;, Proj&gt;, const T*&gt;
constexpr safe_iterator_t&lt;R&gt;
  ranges::remove(R&amp;&amp; r, const T&amp; value, Proj proj = {});

[...]

template&lt;InputIterator I, Sentinel&lt;I&gt; S, WeaklyIncrementable O, class T,
         class Proj = identity&gt;
  requires IndirectlyCopyable&lt;I, O&gt; &amp;&amp;
           Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;I, Proj&gt;, const T*&gt;
  constexpr remove_copy_result&lt;I, O&gt;
    ranges::remove_copy(I first, S last, O result, const T&amp; value, Proj proj = {});

template&lt;InputRange R, WeaklyIncrementable O, class T, class Proj = identity&gt;
  requires IndirectlyCopyable&lt;iterator_t&lt;R&gt;, O&gt; &amp;&amp;
           Indirect<ins>BinaryPredicate</ins><del>Relation</del>&lt;ranges::equal_to, projected&lt;iterator_t&lt;R&gt;, Proj&gt;, const T*&gt;
  constexpr remove_copy_result&lt;safe_iterator_t&lt;R&gt;, O&gt;
    ranges::remove_copy(R&amp;&amp; r, O result, const T&amp; value, Proj proj = {});
</pre>
</blockquote>


<p>Apply following changes to section [alg.unique] Unique:</p>
<blockquote class="std">
<pre>
template&lt;Permutable I, Sentinel&lt;I&gt; S, class Proj = identity,
  Indirect<ins>Equivalence</ins>Relation&lt;projected&lt;I, Proj&gt;&gt; C = ranges::equal_to&gt;
  constexpr I ranges::unique(I first, S last, C comp = {}, Proj proj = {});

template&lt;ForwardRange R, class Proj = identity,
         Indirect<ins>Equivalence</ins>Relation&lt;projected&lt;iterator_t&lt;R&gt;, Proj&gt;&gt; C = ranges::equal_to&gt;
  requires Permutable&lt;iterator_t&lt;R&gt;&gt;
  constexpr safe_iterator_t&lt;R&gt;
    ranges::unique(R&amp;&amp; r, C comp = {}, Proj proj = {});

[...]

template&lt;InputIterator I, Sentinel&lt;I&gt; S, WeaklyIncrementable O,
         class Proj = identity, Indirect<ins>Equivalence</ins>Relation&lt;projected&lt;I, Proj&gt;&gt; C = ranges::equal_to&gt;
  requires IndirectlyCopyable&lt;I, O&gt; &amp;&amp;
           (ForwardIterator&lt;I&gt; ||
            (InputIterator&lt;O&gt; &amp;&amp; Same&lt;iter_value_t&lt;I&gt;, iter_value_t&lt;O&gt;&gt;) ||
            IndirectlyCopyableStorable&lt;I, O&gt;)
  constexpr unique_copy_result&lt;I, O&gt;
    ranges::unique_copy(I first, S last, O result, C comp = {}, Proj proj = {});

template&lt;InputRange R, WeaklyIncrementable O, class Proj = identity,
         Indirect<ins>Equivalence</ins>Relation&lt;projected&lt;iterator_t&lt;R&gt;, Proj&gt;&gt; C = ranges::equal_to&gt;
  requires IndirectlyCopyable&lt;iterator_t&lt;R&gt;, O&gt; &amp;&amp;
          (ForwardIterator&lt;iterator_t&lt;R&gt;&gt; ||
           (InputIterator&lt;O&gt; &amp;&amp; Same&lt;iter_value_t&lt;iterator_t&lt;R&gt;&gt;, iter_value_t&lt;O&gt;&gt;) ||
            IndirectlyCopyableStorable&lt;iterator_t&lt;R&gt;, O&gt;)
  constexpr unique_copy_result&lt;safe_iterator_t&lt;R&gt;, O&gt;
    ranges::unique_copy(R&amp;&amp; r, O result, C comp = {}, Proj proj = {});
</pre>
</blockquote>


<p>Update the value of the <code>__cpp_ranges</code> in table "Standard library feature-test macros" of [support.limits.general] to reflect the date of approval of this proposal.</p>

<h2><a name="implementability">5. Implementability</a></h2>

<p>Implementation of the changes proposed in this paper, may be found in <a href="https://github.com/CaseyCarter/cmcstl2/pull/310">following pull request</a>
   for <a href="https://github.com/CaseyCarter/cmcstl2">cmcstl2</a>.</p>

<h2><a name="acknowledgements">6. Acknowledgements</a></h2>

<p>Special thanks and recognition goes to Sabre (<a href="http://www.sabre.com/">http://www.sabre.com</a>) for supporting the production of this proposal
   and author's participation in standardization committee.</p>

<h2><a name="literature">7. References</a></h2>

<ol>
  <li>Eric Niebler,
      "[Indirect]Relation + non-comparable sentinels and input iterators == :-(",
      (Issue 599, <a href="https://github.com/ericniebler/stl2/issues/599">https://github.com/ericniebler/stl2/issues/599</a>)</li>

  <li>Richard Smith,
      "Working Draft, Standard for Programming Language C++"
      (N4810, <a href="https://wg21.link/n4810">https://wg21.link/n4810</a>)</li>

 <li>Casey Carter et al.,
     "cmcstl2",
     (<a href="https://github.com/CaseyCarter/cmcstl2">https://github.com/CaseyCarter/cmcstl2</a>)</li>

<li>Tomasz Kamiński,
    "Implemented changes from P1716",
     (Pull request #310, <a href="https://github.com/CaseyCarter/cmcstl2/pull/310">https://github.com/CaseyCarter/cmcstl2/pull/310</a>)</li>

</ol>


</body></html>
