<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style type="text/css">
  p {text-align:justify}
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  blockquote.note
  {
   background-color:#E0E0E0;
   padding-left: 15px;
   padding-right: 15px;
   padding-top: 1px;
   padding-bottom: 1px;
  }
  div#refs p { padding-left: 32px; text-indent: -32px; }
</style>

<title>Proposed wording for LWG 2114 (contextually convertible to <tt>bool</tt>)</title>

</head>
<body>
<address style="text-align: left;">
Document number: P2167R2<br>
Date: 2022-06-15<br>
Audience: Library Working Group<br>
Author: Daniel Kr&uuml;gler<br>
Reply-to: <a href="mailto:daniel.kruegler@gmail.com">Daniel Kr&uuml;gler</a>
</address>
<hr>
<h1 style="text-align: center;">Improved Proposed Wording for LWG 2114<br/>(contextually convertible to <tt>bool</tt>)</h1>

<ul>
<li><a href="#Intro">Introduction</a></li>
<li><a href="#RevisionHistory">Revision History</a></li>
<li><a href="#Discussion">Discussion</a></li>
<li><a href="#Rationale">Rationale</a></li>
<li><a href="#QuestionToCommittee">Questions to Committee</a></li>
<li><a href="#ExoticTypes">Exotic Types</a></li>
<li><a href="#Proposed_resolution">Proposed Resolution</a></li>
<li><a href="#Issues_Resolved">Resolved Issues</a></li>
<li><a href="#Proposed_resolution">Proposed Resolution</a></li>
<li><a href="#Akn">Acknowledgements</a></li>
<li><a href="#Bibliography">Bibliography</a></li>
</ul>

<h2><a name="Intro"></a>Introduction</h2>
<p>
This proposal is intended to provide wording to resolve the existing library 
issue <a href="https://wg21.link/lwg2114">LWG 2114</a>.
</p>

<h2><a name="RevisionHistory"></a>Revision History</h2>
<p>
Changes since <a href="https://wg21.link/p2167r1">P2167R1</a>:
</p>
<ul>
<li><p>
Rebase wording to <a href="https://wg21.link/n4910">N4910</a>.
</p></li>
<li><p>
Present four places with <em>mutually exclusive</em> wording alternatives (to be decided for) and add a 
new section <a href="#QuestionToCommittee">Questions to Committee</a> to ensure that
the intended design is ensured and that possible wording alternatives
have been considered and the non-selected ones are intentionally rejected.
</p></li>
<li><p>
Add a new section <a href="#ExoticTypes">Exotic Types</a> that present intentionally exotic types
whose behaviour would change depending on some solution choices.
</p></li>
</ul><p>
Changes since <a href="https://wg21.link/p2167r0">P2167R0</a>:
</p>
<ul>
<li><p>
Remove changes suggested for [valarray.comparison]. For the same reason as e.g. for [optional.relops]
and [reverse.iter.cmp] the result is just converted to <tt>bool</tt> and nothing else is done with it.
</p></li>
<li><p>
Rebase wording to <a href="https://wg21.link/n4892">N4892</a>.
</p></li>
<li><p>
Improve document title.
</p></li>
</ul>

<h2><a name="Discussion"></a>Discussion</h2>
<p>
Issue <a href="https://wg21.link/lwg2114">LWG 2114</a> has already a long history and a number of
wording revisions that went backward and forward. But with the introduction of the <tt><i>boolean-testable</i></tt>
exposition-only concept by <a href="https://wg21.link/p1964r2">P1964R2</a> adopted during the Prague 2020 meeting 
we have now an officially accepted useful tool that can be used to fix this issue.
<p/>
Since the edits of the working draft are not very small, this paper has been written.
</p>

<h2><a name="Rationale"></a>Rationale</h2>
<p>
The <tt><i>boolean-testable</i></tt> concept has all the properties that <a href="https://wg21.link/lwg2114">LWG 2114</a> tried
to specify without having language-concepts available. Our existing terminology of "modeling" a concept should
allow us to use this wording even when we specify something within existing named requirements sets. So the approach
of this paper is just to impose the <tt><i>boolean-testable</i></tt> concept requirements to those places that
the issue identifies, now updated to the most recent working draft.
<p/>
The following guidelines have been chosen to decide for applying the <tt><i>boolean-testable</i></tt> concept 
requirements below:
</p>
<ul>
<li><p>Type families that are potentially influenced by program-defined types, such as types 
meeting the <i>Cpp17NullablePointer</i> requirements, are usually good candidates, unless
the <tt>bool</tt>-like expressions are purposely intended to reflect the exact behaviour 
as presented (The design of the comparison functions of <tt>optional</tt> belong into this category)</p></li>
<li><p>Type families or specifications that solely exist to shorten the specification of
library-provided types, should usually <em>not</em> be good candidates, unless the intention
exists here to provide Library implementors more freedom. An example for this case are
the Container requirements which are actually invented to shorten the specification of the
existing concrete container templates, where all of them use a concrete type <tt>bool</tt> for
<tt>operator==/!=</tt> and for the <tt>empty</tt> function
</p>
</li>
</ul>

<h2><a name="QuestionToCommittee"></a>Questions to Committee</h2>
<p>
The following lists a number of explicit questions the author would like to ask the LWG committee for 
its opinion to ensure that the paper meets its existing design <em>intention</em>. The paper doesn't intend to
change the design intention, but attempts to clarify and possibly harmonize them, so LWG may need to
temporarily forward some of these questions to LEWG. 
</p>
<ol style="list-style-type:none">
<li><p><a href="#questions_1" id="questions_1">1.</a> Regarding 24.2.2.2 [container.reqmts] should for 
the container requirements of <tt>operator==/!=</tt>
and <tt>empty()</tt> the return type <tt>bool</tt> be enforced? According to "gentlemen's agreement" the
container requirements are actually considered as a simplifying means to specify concrete Standard library
container requirements and are not actually representing more general applicable requirements (albeit some
books such as <i>Generic Programming and the STL</i> by Matthew Austern and the 
<a href="https://www.boost.org/sgi/stl/doc_introduction.html">original SGI specification</a> represent this
differently). Currently all library-provided containers (<tt>valarray</tt> is not such thing!) 
do have declared <tt>empty</tt> functions and <tt>operator==/!=</tt> that return <tt>bool</tt>, but we 
may want to support others in the future. This particular change would be not essential for this intended 
bug-fix paper and could be done by an independent proposal if really needed. Two possible
counter arguments against such a change are also that (a) user code could potentially attempt to specialize the
a Standard container template for a program-defined template argument type and this wording change could 
potentially break such a program-defined specialization and (b) this could be a potential unnecessary
restriction for the forward evolution of the Standard Library (Consider a potential future container
type that would like to deviate from a <tt>bool</tt> return type).</p>
<blockquote class="note">
<p>
It should be pointed out that in the past we had considered to take advantage of "convertible to <tt>bool</tt>"
requirements for allocator equality by allowing to implement them as <tt>constexpr</tt> with 
<tt>std::true/false_type</tt> as return types, but with the introduction of the <tt>is_always_equal</tt>
query type of an allocator we had withdrawn this idea, so at the moment we have no need for such
a customization point. If we really want to return to a similar point again, we can easily decide to
change the return type e.g. for container equality again to model <tt><i>boolean-testable</i></tt>, but
now specifically to realize a concrete purpose. But this argument holds only for non-program-defined
(specializations of) container types.
</p>
</blockquote>
<p>
The affected wording location is <a href="#container.reqmts">[container.reqmts]</a>.
</p>
</li>
<li><p><a href="#questions_2" id="questions_2">2.</a> Independent from the previous bullet but based on similar 
arguments as this proposal uses for the currently suggested 24.2.2.2 [container.reqmts] wording changes, the 
wording changes to <tt>fpos</tt> (31.5.3.2 [fpos.operations] Table [tab:fpos.operations]) could similarly be 
strengthened to enforce a <tt>bool</tt> return type for <tt>operator==</tt> and <tt>operator!=</tt>
the argument being that this type is under control of the implementation and all currently inspected
library implementations (libc++, libstdc++, MSVC STL) do already implement this enforcement. A possible
counter against this position could be that user code could potentially attempt to specialize the
<tt>std::pos</tt> template for a program-defined state type and this wording change could potentially break
such a program-defined specialization. The affected wording location is <a href="#fpos.operations">[fpos.operations]</a>.</p></li>
<li><p><a href="#questions_3" id="questions_3">3.</a> Previous revisions of this proposal did only suggest to add 
<tt><i>boolean-testable</i></tt> constraints to <tt>tuple</tt>'s <tt>operator==</tt>, but due to the strong type 
similarity between <tt>pair</tt> and <tt>tuple</tt> one could argue that <tt>pair</tt>'s <tt>operator==</tt> 
should have a similar restriction. The committee should decide which of these positions is more important. 
Adding the <tt><i>boolean-testable</i></tt> could potentially invalidate existing program-defined types for 
<tt>pair</tt>. The affected wording locations are <a href="#pairs.spec">[pairs.spec]</a> and
<a href="#tuple.rel">[tuple.rel]</a>.</p></li>
<li><p><a href="#questions_4" id="questions_4">4.</a> There exist a number of places in the standard wording 
(usually from its older parts), that could be modified as follows (The presented example is from 24.3.9.6 
[forward.list.ops]):</p>
<blockquote>
<pre>
size_type remove(const T&amp; value);
template&lt;class Predicate&gt; size_type remove_if(Predicate pred);
</pre>
<blockquote>
<p>
-13- <i>Effects:</i> Erases all the elements in the list referred to by a list iterator <tt>i</tt> for which the following
conditions hold: <tt><ins>bool(</ins>*i == value<ins>)</ins></tt> (<tt>for remove()</tt>), 
<tt><ins>bool(</ins>pred(*i)<ins>)</ins></tt> is <tt>true</tt> (for <tt>remove_if()</tt>). Invalidates only the 
iterators and references to the erased elements.
<p/>
[&hellip;]
</p>
</blockquote>
<pre>
size_type unique();
template&lt;class BinaryPredicate&gt; size_type unique(BinaryPredicate binary_pred);
</pre>
<blockquote>
<p>
[&hellip;]
<p/>
-20- <i>Effects:</i> Erases all but the first element from every consecutive group of equivalent elements. That is, for
a nonempty list, erases all elements referred to by the iterator <tt>i</tt> in the range <tt>[begin() + 1, end())</tt>
for which <tt><ins>bool(</ins>binary_pred(*i, *(i - 1))<ins>)</ins></tt> is <tt>true</tt>. Invalidates only the iterators 
and references to the erased elements.
<p/>
[&hellip;]
</p>
</blockquote>
</blockquote>
<p>
More modern wording usually uses such an explicit <tt>bool</tt> conversion in corresponding wording, see e.g.
from 25.4.4.2 [range.iter.op.advance]:
</p>
<blockquote>
<pre>
template&lt;input_or_output_iterator I, sentinel_for&lt;I&gt; S&gt;
  constexpr void ranges::advance(I&amp; i, S bound);
</pre>
<blockquote>
<p>
[&hellip;]
<p/>
(4.3) &mdash; Otherwise, while <tt>bool(i != bound)</tt> is <tt>true</tt>, increments <tt>i</tt>.
</p>
</blockquote>
</blockquote>
<p>
This paper <em>could</em> do such additional wording clean-up (but hasn't done yet), but the number of affected 
places is rather large and the required wording effort could reduce the interest on this paper. The author is 
willing to do that work, if the committee prefers it, but doesn't this change would be a necessary part 
of this proposal.
</p>
</li>
</ol>

<h2><a name="ExoticTypes"></a>Exotic Types</h2>
<p>
The following constructed example would potentially cause different behaviour depending on the
selected wording for <tt>pair</tt> and <tt>tuple</tt>. This example is not intended of being
useful, but exist for demonstration purposes only (Note that currently no semantic requirements
are imposed on <tt>operator==</tt> for the presented types).
<p/>
This example would be <em>ill-formed</em> by any of <a href="#pairs.spec_opt_b">[pairs.spec] <b>Option B</b></a>,
<a href="#pairs.spec_opt_c">[pairs.spec] <b>Option C</b></a>, or <a href="#pairs.spec_opt_d">[pairs.spec] <b>Option D</b></a>.
</p>
<blockquote>
<pre>
#include &lt;utility&gt;
#include &lt;tuple&gt;
#include &lt;iostream&gt;

struct A { int val; };
struct B { int val; };
struct EqA { int val; explicit operator bool() const { return val &gt; 0; } };
struct EqB { int val; explicit operator bool() const { return val == 0; } };
struct AndAB { int val; operator bool() const { return val &lt; 0; } };

EqA operator==(A x, A y) { return EqA{x.val + y.val}; }
EqB operator==(B x, B y) { return EqB{x.val + y.val}; }
AndAB operator&amp;&amp;(EqA x, EqB y) { return AndAB{x.val - y.val}; }

int main()
{
  std::pair&lt;A, B&gt; pab1(A{1}, B{2}), pab2(A{4}, B{6});

  // static_assert(!<i>boolean-testable</i>&lt;decltype(pab1.first == pab2.first)&gt;);
  // static_assert(!<i>boolean-testable</i>&lt;decltype(pab1.second == pab2.second)&gt;);
  
  std::cout &lt;&lt; (pab1 == pab2) &lt;&lt; std::endl;
  std::tuple&lt;A, B&gt; tab1(A{1}, B{2}), tab2(A{4}, B{6});
  std::cout &lt;&lt; (tab1 == tab2) &lt;&lt; std::endl;
}
</pre>
<p>
Output according to existing wording:
</p>
<pre>
1
0
</pre>
</blockquote>

<h2><a name="Issues_Resolved"></a>Resolved Issues</h2>
<p>
If the proposed resolution will be accepted, the following library issues will be resolved:
</p>
<table border="1">
  <tr>
    <th>Number</th>
    <th>Description</th>
  </tr>
  <tr>
    <td><a href="https://wg21.link/lwg2114">LWG 2114</a></td>
    <td>Incorrect "<i>contextually</i> convertible to <tt>bool</tt>" requirements</td>
  </tr>
</table> 

<h2><a name="Proposed_resolution"></a>Proposed resolution</h2>

<p>
The proposed wording changes refer to <a href="https://wg21.link/n4910">N4910</a>.
</p>

<ol>
<li><p>Modify in 16.4.4.2 [utility.arg.requirements] Table [tab:cpp17.equalitycomparable] as indicated:</p>

<blockquote>
<table border="1">
<caption>Table 27: <i>Cpp17EqualityComparable</i> requirements [tab:cpp17.equalitycomparable]</caption>

<tr>
<th>Expression</th>
<th>Return type</th>
<th>Requirement</th>
</tr>

<tr>
<td><tt>a == b</tt></td>
<td><del>convertible to <tt>bool</tt></del><br/>
<ins><tt>decltype(a == b)</tt></ins><br/>
<ins>models <tt><i>boolean-testable</i></tt></ins></td>
<td><tt>==</tt> is an equivalence relation, that is, it has the<br/>
following properties: [&hellip;]<br/>
</td>
</tr>

</table>
</blockquote>
</li>

<li><p>Modify in 16.4.4.2 [utility.arg.requirements] Table [tab:cpp17.lessthancomparable] as indicated:</p>

<blockquote>
<table border="1">
<caption>Table 28: <i>Cpp17LessThanComparable</i> requirements [tab:cpp17.lessthancomparable]</caption>

<tr>
<th>Expression</th>
<th>Return type</th>
<th>Requirement</th>
</tr>

<tr>
<td><tt>a &lt; b</tt></td>
<td><del>convertible to <tt>bool</tt></del><br/>
<ins><tt>decltype(a &lt; b)</tt></ins><br/>
<ins>models <tt><i>boolean-testable</i></tt></ins></td>
<td><tt>&lt;</tt> is a strict weak ordering relation (27.8 [alg.sorting])<br/>
</td>
</tr>

</table>
</blockquote>
</li>

<li><p>Modify in 16.4.4.4 [nullablepointer.requirements] Table [tab:cpp17.nullablepointer] as indicated:</p>

<blockquote>

<table border="1">
<caption>Table 35: <i>Cpp17NullablePointer</i> requirements [tab:cpp17.nullablepointer]</caption>

<tr>
<th>Expression</th>
<th>Return type</th>
<th>Operational semantics</th>
</tr>

<tr>
<td colspan="3" style="text-align:center;">&hellip;</td> 
</tr>

<tr>
<td><tt>a != b</tt></td>
<td><del>contextually convertible to <tt>bool</tt></del><br/>
<ins><tt>decltype(a != b)</tt></ins><br/>
<ins>models <tt><i>boolean-testable</i></tt></ins></td>
<td><tt>!(a == b)</tt></td>
</tr>

<tr>
<td><tt>a == np<br/>np == a</tt></td>
<td><del>contextually convertible to <tt>bool</tt></del><br/>
<ins><tt>decltype(a == np)</tt> and <tt>decltype(np == a)</tt></ins><br/>
<ins>both model <tt><i>boolean-testable</i></tt></ins></td>
<td><tt>a == P()</tt></td>
</tr>

<tr>
<td><tt>a != np<br/>np != a</tt></td>
<td><del>contextually convertible to <tt>bool</tt></del><br/>
<ins><tt>decltype(a != np)</tt> and <tt>decltype(np != a)</tt></ins><br/>
<ins>both model <tt><i>boolean-testable</i></tt></ins></td>
<td><tt>!(a == np)</tt></td>
</tr>

</table>
</blockquote>
</li>

<li><p>Modify 17.11.6 [cmp.alg] as indicated:</p>

<blockquote>
<p>[&hellip;]</p>
<p>
-4- The name <tt>compare_strong_order_fallback</tt> denotes a customization point object (16.3.3.3.6 [customization.point.object]). 
Given subexpressions <tt>E</tt> and <tt>F</tt>, the expression <tt>compare_strong_order_fallback(E, F)</tt> is 
expression-equivalent (3.21 [defns.expression.equivalent]) to:
</p>
<ol style="list-style-type: none">
<li><p>[&hellip;]</p></li>
<li><p>(4.3) &mdash; Otherwise, if the expressions <tt>E == F</tt> and <tt>E &lt; F</tt> are both well-formed and 
<del>convertible to <tt>bool</tt></del><ins>the types <tt>decltype(E == F)</tt> and <tt>decltype(E &lt; F)</tt> 
both model <tt><i>boolean-testable</i></tt></ins>,</p>
<blockquote><pre>
E == F ? strong_ordering::equal :
E &lt; F  ? strong_ordering::less :
         strong_ordering::greater
</pre></blockquote>
<p>
except that <tt>E</tt> and <tt>F</tt> are evaluated only once.
</p>
</li>
<li><p>[&hellip;]</p></li>
</ol>
<p>
[&hellip;]
<p/>
-5- The name <tt>compare_weak_order_fallback</tt> denotes a customization point object (16.3.3.3.6 [customization.point.object]). 
Given subexpressions <tt>E</tt> and <tt>F</tt>, the expression <tt>compare_weak_order_fallback(E, F)</tt> is 
expression-equivalent (3.21 [defns.expression.equivalent]) to:
</p>
<ol style="list-style-type: none">
<li><p>[&hellip;]</p></li>
<li><p>(5.3) &mdash; Otherwise, if the expressions <tt>E == F</tt> and <tt>E &lt; F</tt> are both well-formed and 
<del>convertible to <tt>bool</tt></del><ins>the types <tt>decltype(E == F)</tt> and <tt>decltype(E &lt; F)</tt> 
both model <tt><i>boolean-testable</i></tt></ins>,</p>
<blockquote><pre>
E == F ? weak_ordering::equivalent :
E &lt; F  ? weak_ordering::less :
         weak_ordering::greater
</pre></blockquote>
<p>
except that <tt>E</tt> and <tt>F</tt> are evaluated only once.
</p>
</li>
<li><p>[&hellip;]</p></li>
</ol>
<p>
[&hellip;]
<p/>
-6- The name <tt>compare_partial_order_fallback</tt> denotes a customization point object (16.3.3.3.6 [customization.point.object]). 
Given subexpressions <tt>E</tt> and <tt>F</tt>, the expression <tt>compare_partial_order_fallback(E, F)</tt> is 
expression-equivalent (3.21 [defns.expression.equivalent]) to:
</p>
<ol style="list-style-type: none">
<li><p>[&hellip;]</p></li>
<li><p>(6.3) &mdash; Otherwise, if the expressions <tt>E == F</tt> and <tt>E &lt; F</tt> are both well-formed and 
<del>convertible to <tt>bool</tt></del><ins>the types <tt>decltype(E == F)</tt> and <tt>decltype(E &lt; F)</tt> 
both model <tt><i>boolean-testable</i></tt></ins>,</p>
<blockquote><pre>
E == F ? partial_ordering::equivalent :
E &lt; F  ? partial_ordering::less :
E &gt; F  ? partial_ordering::greater :
         partial_ordering::unordered
</pre></blockquote>
<p>
except that <tt>E</tt> and <tt>F</tt> are evaluated only once.
</p>
</li>
<li><p>[&hellip;]</p></li>
</ol>
</blockquote>

</li>

<li><p>Keep 21.3.9 [meta.logical] unchanged: These logical type traits do already the boolean logic for you, and 
no further requirements are imposed.</p>
</li>

<li><p><a href="#pairs.spec" id="pairs.spec">[pairs.spec]</a> Modify 22.3.3 [pairs.spec] as indicated:</p>

<blockquote class="note">
<p>
[<i>Drafting note:</i> Four mutually exclusive options denoted by <a href="#pairs.spec_opt_a"><b>Option A</b></a>, 
<a href="#pairs.spec_opt_b"><b>Option B</b></a>, <a href="#pairs.spec_opt_c"><b>Option C</b></a>, and 
<a href="#pairs.spec_opt_d"><b>Option D</b></a> are presented with increasing strictness, see also 
<a href="#questions_3">Questions to Committee bullet 3</a>.]
</p>
</blockquote>

<p>
<a href="#pairs.spec_opt_a" id="pairs.spec_opt_a"><b>Option A:</b></a> Perform no changes and keep supporting element types where no <em>individual</em> requirements 
are imposed on <tt>p1.first == p2.first</tt> or <tt>p1.second == p2.second</tt>.
</p>

<blockquote>
<blockquote><pre>
template&lt;class T1, class T2&gt;
  constexpr bool operator==(const pair&lt;T1, T2&gt;&amp; x, const pair&lt;T1, T2&gt;&amp; y);
</pre>
<blockquote>
<p>
-1- <i>Returns:</i> <tt>x.first == y.first &amp;&amp; x.second == y.second</tt>.
</p>
</blockquote>
</blockquote>
</blockquote>

<p>
<a href="#pairs.spec_opt_b" id="pairs.spec_opt_b"><b>Option B:</b></a> Is in sync with the specification of <tt>pair</tt>'s
<tt>operator&lt;=&gt;</tt> and harmonizes <tt>operator==</tt> with the behaviour of a defaulted one (11.10.2 [class.eq]).
This solution harmonizes best with that of <a href="#tuple.rel_opt_a">[tuple.rel] <b>Option A</b></a>.
</p>

<blockquote>
<blockquote><pre>
template&lt;class T1, class T2&gt;
  constexpr bool operator==(const pair&lt;T1, T2&gt;&amp; x, const pair&lt;T1, T2&gt;&amp; y);
</pre>
<blockquote>
<p>
-1- <i><del>Returns</del><ins>Effects</ins>:</i> <ins>Equivalent to:</ins><del><tt>x.first == y.first &amp;&amp; x.second == y.second</tt>.</del>
</p>
<blockquote><pre>
<ins>if (bool b = (x.first == y.first); !b) return false;
return x.second == y.second;</ins>
</pre></blockquote>
</blockquote>
</blockquote>
</blockquote>

<p>
<a href="#pairs.spec_opt_c" id="pairs.spec_opt_c"><b>Option C:</b></a> Require that the individual expressions
<tt>p1.first == p2.first</tt> and <tt>p1.second == p2.second</tt> model <tt><i>boolean-testable</i></tt>, harmonizing
the corresponding requirements for <tt>operator==</tt> of <tt>pair</tt> and <tt>tuple</tt>.
This solution harmonizes best with that of <a href="#tuple.rel_opt_b">[tuple.rel] <b>Option B</b></a>.
</p>

<blockquote>
<blockquote><pre>
template&lt;class T1, class T2&gt;
  constexpr bool operator==(const pair&lt;T1, T2&gt;&amp; x, const pair&lt;T1, T2&gt;&amp; y);
</pre>
<blockquote>
<p>
<ins>-?- <i>Mandates:</i> <tt>decltype(x.first == y.first)</tt> models <tt><i>boolean-testable</i></tt>
and <tt>decltype(x.second == y.second)</tt> models <tt><i>boolean-testable</i></tt>.</ins>
<p/>
-1- <i>Returns:</i> <tt>x.first == y.first &amp;&amp; x.second == y.second</tt>.
</p>
</blockquote>
</blockquote>
</blockquote>

<p>
<a href="#pairs.spec_opt_d" id="pairs.spec_opt_d"><b>Option D:</b></a> Combines both 
<a href="#pairs.spec_opt_b"><b>Option B</b></a> and <a href="#pairs.spec_opt_c"><b>Option C</b></a>,
but enforces the same expression semantics as for <tt>tuple</tt> and is in sync with the specification of <tt>pair</tt>'s
<tt>operator&lt;=&gt;</tt>. This solution also harmonizes <tt>operator==</tt> with the behaviour of a defaulted one
(11.10.2 [class.eq]).
</p>

<blockquote>
<blockquote><pre>
template&lt;class T1, class T2&gt;
  constexpr bool operator==(const pair&lt;T1, T2&gt;&amp; x, const pair&lt;T1, T2&gt;&amp; y);
</pre>
<blockquote>
<p>
<ins>-?- <i>Mandates:</i> <tt>decltype(x.first == y.first)</tt> models <tt><i>boolean-testable</i></tt>
and <tt>decltype(x.second == y.second)</tt> models <tt><i>boolean-testable</i></tt>.</ins>
<p/>
-1- <i><del>Returns</del><ins>Effects</ins>:</i> <ins>Equivalent to:</ins><del><tt>x.first == y.first &amp;&amp; x.second == y.second</tt>.</del>
</p>
<blockquote><pre>
<ins>if (bool b = (x.first == y.first); !b) return false;
return x.second == y.second;</ins>
</pre></blockquote>
</blockquote>
</blockquote>
</blockquote>

</li>

<li><p><a href="#tuple.rel" id="tuple.rel">[tuple.rel]</a> Modify 22.4.8 [tuple.rel] as indicated:</p>

<blockquote class="note">
<p>
[<i>Drafting note:</i> Two mutually exclusive options denoted by <a href="#tuple.rel_opt_a"><b>Option A</b></a> 
and <a href="#tuple.rel_opt_b"><b>Option B</b></a> are presented with increasing strictness, see also 
<a href="#questions_3">Questions to Committee bullet 3</a>.]
</p>
</blockquote>

<p>
<a href="#tuple.rel_opt_a" id="tuple.rel_opt_a"><b>Option A:</b></a> Harmonize wording with that of
<tt>tuple</tt>'s <tt>operator&lt;=&gt;</tt> and effectively don't change existing requirements. This 
solution harmonizes best with that of <a href="#pairs.spec_opt_b">[pairs.spec] <b>Option B</b></a>.
</p>

<blockquote><pre>
template&lt;class... TTypes, class... UTypes&gt;
  constexpr bool operator==(const tuple&lt;TTypes...&gt;&amp; t, const tuple&lt;UTypes...&gt;&amp; u);
</pre>
<blockquote>
<p>
-1- <i>Mandates:</i> <del>For all <tt>i</tt>, where <tt>0 &le; i &lt; sizeof...(TTypes)</tt>, 
<tt>get&lt;i&gt;(t) == get&lt;i&gt;(u)</tt> is a valid expression returning a type that 
is convertible to <tt>bool</tt>.</del> <tt>sizeof...(TTypes)</tt> equals <tt>sizeof...(UTypes)</tt>.
<p/>
-2- <i><del>Returns</del><ins>Effects</ins>:</i> <del><tt>true</tt> if <tt>get&lt;i&gt;(t) == get&lt;i&gt;(u)</tt> 
for all <tt>i</tt>, otherwise <tt>false</tt>. For any two zero-length tuples <tt>e</tt> and <tt>f</tt>, <tt>e == f</tt> 
returns <tt>true</tt>.</del><ins>Performs an equality comparison between <tt>t</tt> and <tt>u</tt>. For any two 
zero-length tuples <tt>t</tt> and <tt>u</tt>, <tt>t == u</tt> returns <tt>true</tt>. Otherwise, equivalent to:</ins>
</p>
<blockquote><pre>
<ins>if (bool b = (get&lt;0&gt;(t) == get&lt;0&gt;(u)); !b) return false;
return t<sub>tail</sub> == u<sub>tail</sub>;</ins>
</pre></blockquote>
<p>
<ins>where <tt>r<sub>tail</sub></tt> for some tuple <tt>r</tt> is a tuple containing all but the first element of <tt>r</tt>.</ins>
<p/>
-3- <del><i>Remarks:</i> The elementary comparisons are performed in order from the zeroth index upwards. No
comparisons or element accesses are performed after the first equality comparison that evaluates to
<tt>false</tt>.</del><ins>[<i>Note ?</i>: The above definition does not require <tt>t<sub>tail</sub></tt> (or 
<tt>u<sub>tail</sub></tt>) to be constructed. It might not even be possible, as <tt>t</tt> and <tt>u</tt> are 
not required to be copy constructible. Also, all equality operator functions are short circuited; they do
not perform element accesses beyond what is required to determine the result of the comparison. &mdash; <i>end note</i>]</ins>
</p>
</blockquote>
</blockquote>

<p>
<a href="#tuple.rel_opt_b" id="tuple.rel_opt_b"><b>Option B:</b></a> Strengthen the "convertible to <tt>bool</tt>" requirement
to <tt><i>boolean-testable</i></tt>. This solution harmonizes best with that of <a href="#pairs.spec_opt_c">[pairs.spec] 
<b>Option C</b></a>.
</p>

<blockquote><pre>
template&lt;class... TTypes, class... UTypes&gt;
  constexpr bool operator==(const tuple&lt;TTypes...&gt;&amp; t, const tuple&lt;UTypes...&gt;&amp; u);
</pre>
<blockquote>
<p>
-1- <i>Mandates:</i> For all <tt>i</tt>, where <tt>0 &le; i &lt; sizeof...(TTypes)</tt>, 
<tt>get&lt;i&gt;(t) == get&lt;i&gt;(u)</tt> is a valid expression <del>returning a type that 
is convertible to <tt>bool</tt></del><ins>and the type <tt>decltype(get&lt;i&gt;(t) == get&lt;i&gt;(u))</tt> 
models <tt><i>boolean-testable</i></tt></ins>. <tt>sizeof...(TTypes)</tt> equals <tt>sizeof...(UTypes)</tt>.
<p/>
[&hellip;]
</p>
</blockquote>
</blockquote>

</li>

<li><p>Keep 22.5.6 [optional.relops] unchanged: These operations just evaluate what they get and say, and no further 
requirements are imposed.</p>
</li>

<li><p>Keep 22.5.8 [optional.comp.with.t] unchanged: These operations just evaluate what they get and say, and no further 
requirements are imposed.</p>
</li>

<li><p>Keep 22.6.6 [variant.relops] unchanged: These operations just evaluate what they get and say, and no further 
requirements are imposed.</p>
</li>

<li><p>Keep 22.8.3.2.5 [expected.un.eq] unchanged: These operations just evaluate what they get and say, and no further 
requirements are imposed.</p>
</li>

<li><p>Keep 22.8.6.7 [expected.object.eq] unchanged: These operations just evaluate what they get and say, and no further 
requirements are imposed.</p>
</li>

<li><p>Keep 22.8.7.7 [expected.void.eq] unchanged: These operations just evaluate what they get and say, and no further 
requirements are imposed.</p>
</li>

<li><p><a href="#container.reqmts" id="container.reqmts">[container.reqmts]</a> Modify 
24.2.2.2 [container.reqmts] as indicated:</p>

<blockquote class="note">
<p>
[<i>Drafting note:</i> Two mutually exclusive options denoted by <a href="#container.reqmts_opt_a"><b>Option A</b></a> 
and <a href="#container.reqmts_opt_b"><b>Option B</b></a> are presented, see also 
<a href="#questions_1">Questions to Committee bullet 1</a>.]
</p>
</blockquote>

<p>
<a href="#container.reqmts_opt_a" id="container.reqmts_opt_a"><b>Option A:</b></a> Impose the relaxed freedom to 
use any type modeling <tt><i>boolean-testable</i></tt> for <tt>operator==/!=</tt> and <tt>empty</tt>.
</p>

<blockquote class="note">
<p>
[<i>Drafting note:</i> The <tt><i>boolean-testable</i></tt> requirements already impose that the negation of the
equality result also has to model <tt><i>boolean-testable</i></tt>, so no additional restrictions to <tt>a != b</tt>
are necessary.]
</p>
</blockquote>

<blockquote>
<p>
[&hellip;]
</p>
<pre>
a == b
</pre>
<blockquote>
<p>
-39- <i>Preconditions:</i> <tt>T</tt> meets the <i>Cpp17EqualityComparable</i> requirements.
<p/>
-40- <i>Result:</i> <del>Convertible to <tt>bool</tt></del><ins><tt>decltype(a == b)</tt> models <tt><i>boolean-testable</i></tt></ins>.
<p/>
-41- <i>Returns:</i> <tt>equal(a.begin(), a.end(), b.begin(), b.end())</tt>
<p/>
[&hellip;]
<p/>
-43- <i>Remarks:</i> <tt>==</tt> is an equivalence relation.
</p>
</blockquote>
<pre>
a != b
</pre>
<blockquote>
<p>
-44- <i>Effects:</i> Equivalent to <tt>!(a == b)</tt>.
</p>
</blockquote>
<p>
[&hellip;]
</p>
<pre>
a.empty()
</pre>
<blockquote>
<p>
-59- <i>Result:</i> <del>Convertible to <tt>bool</tt></del><ins><tt>decltype(a.empty())</tt> models <tt><i>boolean-testable</i></tt></ins>.
<p/>
-60- <i>Returns:</i> <tt>a.begin() == a.end()</tt>
<p/>
-61- <i>Complexity:</i> Constant.
<p/>
-62- <i>Remarks:</i> If the container is empty, then <tt><ins>bool(</ins>a.empty()<ins>)</ins></tt> is <tt>true</tt>.
</p>
</blockquote>
</blockquote>

<p>
<a href="#container.reqmts_opt_b" id="container.reqmts_opt_b"><b>Option B:</b></a> Enforce <tt>bool</tt> return type 
for <tt>operator==/!=</tt> and <tt>empty</tt>.
</p>

<blockquote>
<p>
[&hellip;]
</p>
<pre>
a == b
</pre>
<blockquote>
<p>
-39- <i>Preconditions:</i> <tt>T</tt> meets the <i>Cpp17EqualityComparable</i> requirements.
<p/>
-40- <i>Result:</i> <del>Convertible to</del> <tt>bool</tt>.
<p/>
-41- <i>Returns:</i> <tt>equal(a.begin(), a.end(), b.begin(), b.end())</tt>
<p/>
[&hellip;]
<p/>
-43- <i>Remarks:</i> <tt>==</tt> is an equivalence relation.
</p>
</blockquote>
<pre>
a != b
</pre>
<blockquote>
<p>
-44- <i>Effects:</i> Equivalent to <tt>!(a == b)</tt>.
</p>
</blockquote>
<p>
[&hellip;]
</p>
<pre>
a.empty()
</pre>
<blockquote>
<p>
-59- <i>Result:</i> <del>Convertible to</del> <tt>bool</tt>.
<p/>
-60- <i>Returns:</i> <tt>a.begin() == a.end()</tt>
<p/>
-61- <i>Complexity:</i> Constant.
<p/>
-62- <i>Remarks:</i> If the container is empty, then <tt>a.empty()</tt> is <tt>true</tt>.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Keep 25.3.4.4 [iterator.concept.winc] unchanged: It seems to me that sufficient wording exists to exclude
funny integer-class types, and they are all under control by the implementation.</p>
</li>

<li><p>Modify in 25.3.5 [iterator.cpp17] Table [tab:inputiterator] and Table [tab:randomaccessiterator] as indicated:</p>

<blockquote>

<table border="1">
<caption>Table 83: <i>Cpp17InputIterator</i> requirements (in addition to <i>Cpp17Iterator</i>) [tab:inputiterator]</caption>

<tr>
<th>Expression</th>
<th>Return type</th>
<th>Operational<br/>semantics</th>
<th>Assertion/note<br/>pre-/post-condition</th>
</tr>

<tr>
<td><tt>a != b</tt></td>
<td><del>contextually convertible to <tt>bool</tt></del><br/>
<ins><tt>decltype(a != b)</tt></ins><br/>
<ins>models <tt><i>boolean-testable</i></tt></ins></td>
<td><tt>!(a == b)</tt></td>
<td>[&hellip;]</td>
</tr>

<tr>
<td colspan="4" style="text-align:center;">&hellip;</td> 
</tr>

</table>
<p>
[&hellip;]
</p>
<table border="1">
<caption>Table 87: <i>Cpp17RandomAccessIterator</i> requirements (in addition to <i>Cpp17BidirectionalIterator</i>)
[tab:randomaccessiterator]</caption>

<tr>
<th>Expression</th>
<th>Return type</th>
<th>Operational<br/>semantics</th>
<th>Assertion/note<br/>pre-/post-condition</th>
</tr>

<tr>
<td colspan="4" style="text-align:center;">&hellip;</td> 
</tr>

<tr>
<td><tt>a &lt; b</tt></td>
<td><del>contextually convertible to <tt>bool</tt></del><br/>
<ins><tt>decltype(a &lt; b)</tt></ins><br/>
<ins>models <tt><i>boolean-testable</i></tt></ins></td>
<td><i>Effects:</i> Equivalent to: <tt>return<br/>b - a &gt; 0;</tt></td>
<td>[&hellip;]</td>
</tr>

<tr>
<td><tt>a &gt; b</tt></td>
<td><del>contextually convertible to <tt>bool</tt></del><br/>
<ins><tt>decltype(a &gt; b)</tt></ins><br/>
<ins>models <tt><i>boolean-testable</i></tt></ins></td>
<td><tt>b &lt; a</tt></td>
<td>[&hellip;]</td>
</tr>

<tr>
<td><tt>a &gt;= b</tt></td>
<td><del>contextually convertible to <tt>bool</tt></del><br/>
<ins><tt>decltype(a &gt;= b)</tt></ins><br/>
<ins>models <tt><i>boolean-testable</i></tt></ins></td>
<td><tt>!(a &lt; b)</tt></td>
<td>[&hellip;]</td>
</tr>

<tr>
<td><tt>a &lt;= b</tt></td>
<td><del>contextually convertible to <tt>bool</tt></del><br/>
<ins><tt>decltype(a &lt;= b)</tt></ins><br/>
<ins>models <tt><i>boolean-testable</i></tt></ins></td>
<td><tt>!(a &gt; b)</tt></td>
<td>[&hellip;]</td>
</tr>

</table>
</blockquote>
</li>

<li><p>Keep 25.5.1.8 [reverse.iter.cmp] unchanged: These operations just evaluate what they get and say, and no further 
requirements are imposed.</p>
</li>

<li><p>Keep 25.5.3.8 [move.iter.op.comp] unchanged: These operations just evaluate what they get and say, and no further 
requirements are imposed.</p>
</li>

<li><p>Modify 27.2 [algorithms.requirements] as indicated:</p>

<blockquote class="note">
<p>
[<i>Drafting note:</i> The wording changes below also fix (a) unusual wording forms used ("should work") which are unclear 
in which sense they are imposing normative requirements and (b) the problem, that the current wording seems to allow 
that the predicate may mutate a call argument, if that is not a dereferenced iterator. Upon applying the new wording 
it became obvious that the both the previous and the new wording has the effect that currently algorithms such as 
<tt>adjacent_find</tt>, <tt>search_n</tt>, <tt>unique</tt>, and <tt>unique_copy</tt> are not correctly described 
(because they have no iterator argument named <tt>first1</tt>), which could give raise to a new library issue. ]
</p>
</blockquote>

<blockquote>
<p>
-7- When not otherwise constrained, the <tt>Predicate</tt> parameter is used whenever an algorithm expects a function
object (22.10 [function.objects]) that, when applied to the result of dereferencing the corresponding iterator, 
returns a value testable as <tt>true</tt>. I<del>n other words, i</del>f an algorithm takes <tt>Predicate pred</tt> as its 
argument and <tt>first</tt> as its iterator argument with value type <tt>T</tt>, <del>it should work correctly in the 
construct <tt>pred(*first)</tt> contextually converted to <tt>bool</tt> (7.3 [conv])</del><ins>the expression
<tt>pred(*first)</tt> shall be well-formed and the type <tt>decltype(pred(*first))</tt> shall model 
<tt><i>boolean-testable</i></tt> (18.5.2 [concept.booleantestable])</ins>. 
The function object <tt>pred</tt> shall not apply any non-constant function through <del>the dereferenced 
iterator</del><ins>its argument</ins>. Given a glvalue <tt>u</tt> of type (possibly <tt>const</tt>) <tt>T</tt> that 
designates the same object as <tt>*first</tt>, <tt>pred(u)</tt> shall be a valid expression that is equal to <tt>pred(*first)</tt>.
<p/>
-8- When not otherwise constrained, the <tt>BinaryPredicate</tt> 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 <tt>T</tt> when <tt>T</tt> is part of the signature returns a value testable as <tt>true</tt>. 
I<del>n other words, i</del>f an algorithm takes <tt>BinaryPredicate binary_pred</tt> as its argument and <tt>first1</tt> 
and <tt>first2</tt> as its iterator arguments with respective value types <tt>T1</tt> and <tt>T2</tt>, <del>it should 
work correctly in the construct <tt>binary_pred(*first1, *first2)</tt> contextually converted to <tt>bool</tt> 
(7.3 [conv])</del><ins>the expression <tt>binary_pred(*first1, *first2)</tt> shall be well-formed and the type 
<tt>decltype(binary_pred(*first1, *first2))</tt> shall model <tt><i>boolean-testable</i></tt></ins>. Unless otherwise specified, <tt>BinaryPredicate</tt> always takes the 
first iterator's <tt>value_type</tt> as its first argument, that is, in those cases when <tt>T value</tt> is part 
of the signature, <del>it should work correctly in the construct <tt>binary_pred(*first1, value)</tt> contextually 
converted to <tt>bool</tt> (7.3 [conv])</del><ins>the expression <tt>binary_pred(*first1, value)</tt> shall be 
well-formed and the type <tt>decltype(binary_pred(*first1, value))</tt> shall model <tt><i>boolean-testable</i></tt></ins>. 
<tt>binary_pred</tt> shall not apply any non-constant function through <del>the dereferenced iterators</del><ins>any 
of its arguments</ins>. Given a glvalue <tt>u</tt> of type (possibly <tt>const</tt>) <tt>T1</tt> that designates 
the same object as <tt>*first1</tt>, and a glvalue v of type (possibly <tt>const</tt>) <tt>T2</tt> that designates 
the same object as <tt>*first2</tt>, <tt>binary_pred(u, *first2)</tt>, <tt>binary_pred(*first1, v)</tt>, and 
<tt>binary_pred(u, v)</tt> shall each be a valid expression that is equal to <tt>binary_pred(*first1, *first2)</tt>, 
and <tt>binary_pred(u, value)</tt> shall be a valid expression that is equal to <tt>binary_pred(*first1, value)</tt>.
</p>

</blockquote>
</li>

<li><p>Modify 27.8.1 [alg.sorting.general] as indicated:</p>

<blockquote class="note">
<p>
[<i>Drafting note:</i> The existing wording inherits all the good wording from <tt>BinaryPredicate</tt>,
that we fixed above, so there is only little to do but specifying the conversion to <tt>bool</tt> less strict,
since we already know that it is a type that models <tt><i>boolean-testable</i></tt>]
</p>
</blockquote>

<blockquote>
<p>
-2- <tt>Compare</tt> is a function object type (22.10 [function.objects]) that meets the requirements for 
a template parameter named <tt>BinaryPredicate</tt> (27.2 [algorithms.requirements]). The return value 
of the function call operation applied to an object of type <tt>Compare</tt>, when <del>contextually</del> converted 
to <tt>bool</tt> <del>(7.3 [conv])</del>, yields <tt>true</tt> if the first argument of the call is less than the second,
and <tt>false</tt> otherwise. <tt>Compare comp</tt> is used throughout for algorithms assuming an ordering relation.
</p>

</blockquote>
</li>

<li><p>Keep 28.6.3.2 [valarray.comparison] unchanged: These operations just evaluate what they get and say, and no further 
requirements are imposed.</p>
</li>

<li><p><a href="#fpos.operations" id="fpos.operations">[fpos.operations]</a> Modify in 31.5.3.2 [fpos.operations] 
Table [tab:fpos.operations] as indicated:</p>

<blockquote class="note">
<p>
[<i>Drafting note:</i> Two mutually exclusive options denoted by <a href="#fpos.operations_opt_a"><b>Option A</b></a> 
and <a href="#fpos.operations_opt_b"><b>Option B</b></a> are presented, see also 
<a href="#questions_2">Questions to Committee bullet 2</a>.]
</p>
</blockquote>

<p>
<a href="#fpos.operations_opt_a" id="fpos.operations_opt_a"><b>Option A:</b></a> Impose the relaxed library freedom 
to use any type modeling <tt><i>boolean-testable</i></tt> for <tt>operator==/!=</tt>.
</p>

<blockquote>
<table border="1">
<caption>Table 119: Position type requirements [tab:fpos.operations]</caption>

<tr>
<th>Expression</th>
<th>Return type</th>
<th>Operational<br/>semantics</th>
<th>Assertion/note<br/>pre-/post-condition</th>
</tr>

<tr>
<td colspan="4" style="text-align:center;">&hellip;</td> 
</tr>

<tr>
<td><tt>p != q</tt></td>
<td><del>convertible to <tt>bool</tt></del><br/>
<ins><tt>decltype(p != q)</tt></ins><br/>
<ins>models <tt><i>boolean-testable</i></tt></ins></td>
<td><tt>!(p == q)</tt></td>
<td></td>
</tr>

<tr>
<td colspan="4" style="text-align:center;">&hellip;</td> 
</tr>

</table>
</blockquote>

<p>
<a href="#fpos.operations_opt_b" id="fpos.operations_opt_b"><b>Option B:</b></a> Enforce <tt>bool</tt> 
return type for <tt>operator==/!=</tt>.
</p>

<blockquote class="note">
<p>
[<i>Drafting note:</i> The properties of <tt>operator==</tt> <em>except</em> its more specific return
type are all specified by <i>Cpp17EqualityComparable</i> (See 31.5.3.2 [fpos.operations] p1).
The wording change suggested here does <em>not</em> attempt to resolve <a href="https://wg21.link/lwg3118">LWG 3118</a>.]
</p>
</blockquote>

<blockquote>

<table border="1">
<caption>Table 119: Position type requirements [tab:fpos.operations]</caption>

<tr>
<th>Expression</th>
<th>Return type</th>
<th>Operational<br/>semantics</th>
<th>Assertion/note<br/>pre-/post-condition</th>
</tr>

<tr>
<td colspan="4" style="text-align:center;">&hellip;</td> 
</tr>

<tr>
<td><ins><tt>p == q</tt></ins></td>
<td><ins><tt>bool</tt></ins></td>
<td></td>
<td></td>
</tr>

<tr>
<td><tt>p != q</tt></td>
<td><del>convertible to</del> <tt>bool</tt></td>
<td><tt>!(p == q)</tt></td>
<td></td>
</tr>

<tr>
<td colspan="4" style="text-align:center;">&hellip;</td> 
</tr>

</table>
</blockquote>
</li>

<li><p>Modify 33.2.1 [thread.req.paramname] as indicated:</p>

<blockquote class="note">
<p>
[<i>Drafting note:</i> The following performs some minor drive-by fixes to fix minor wording issues
that would e.g. exclude normal function pointers to be used as predicate. Note that we intentionally
do <em>not</em> describe a potentially <tt>const</tt> lvalue <tt>pred</tt>, since there is nothing 
in the specification that would imply or require that.]
</p>
</blockquote>

<blockquote>
<p>
-1- Throughout this Clause, the names of template parameters are used to express type requirements. <del>If a
template parameter is named <tt>Predicate</tt>, <tt>operator()</tt> applied to the template argument 
shall return a value that is convertible to <tt>bool</tt></del><ins><tt>Predicate</tt> is a function object type 
(22.10 [function.objects]). Let <tt>pred</tt> denote an lvalue of type <tt>Predicate</tt>. Then the
expression <tt>pred()</tt> shall be well-formed and the type <tt>decltype(pred())</tt> shall model 
<tt><i>boolean-testable</i></tt> (18.5.2 [concept.booleantestable]). 
The return value of <tt>pred()</tt>, converted to <tt>bool</tt>, yields <tt>true</tt> if the corresponding 
test condition is satisfied, and <tt>false</tt> otherwise</ins>. [&hellip;]
</p>

</blockquote>
</li>
</ol>

<h2><a name="Akn"></a>Acknowledgements</h2>
<p>
Thanks to Barry Revzin, Tim Song, and Tomasz Kami&nacute;ski for reviewing this proposal and providing helpful 
improvement suggestions.
</p>

<h2><a name="Bibliography"></a>Bibliography</h2>

<div id="refs">
<div id="ref-N4910">
<p>
[N4910] Thomas K&ouml;ppe: "Working Draft, Standard for Programming Language C++", 2022<br/>
<a href="https://wg21.link/n4910">https://wg21.link/n4910</a>
</p>
</div>

<div id="ref-P1964R2">
<p>
[P1964R2] Tim Song: "Wording for <i>boolean-testable</i>", 2020<br/>
<a href="https://wg21.link/p1964r2">https://wg21.link/p1964r2</a>
</p>
</div>

<div id="ref-LWG-2114">
<p>
[LWG2114] Daniel Kr&uuml;gler: "Incorrect "<i>contextually</i> convertible to <tt>bool</tt>" requirements", 2011<br/>
<a href="https://wg21.link/lwg2114">https://wg21.link/lwg2114</a>
</p>
</div>

<div id="ref-Aus2001">
<p>
[Aus2001] Matthew H. Austern: "Generic Programming and the STL", 2001, Addison-Wesley
</p>
</div>
</div>

</body></html>