Skip to content

Commit 46f90d8

Browse files
committed
New issue from Hewill Kang: "std::indirect's operator== still does not support incomplete types"
1 parent c5866c6 commit 46f90d8

File tree

1 file changed

+121
-0
lines changed

1 file changed

+121
-0
lines changed

xml/issue4325.xml

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
<?xml version='1.0' encoding='utf-8' standalone='no'?>
2+
<!DOCTYPE issue SYSTEM "lwg-issue.dtd">
3+
4+
<issue num="4325" status="New">
5+
<title>`std::indirect`'s `operator==` still does not support incomplete types</title>
6+
<section>
7+
<sref ref="[indirect.relops]"/>
8+
<sref ref="[indirect.comp.with.t]"/>
9+
</section>
10+
<submitter>Hewill Kang</submitter>
11+
<date>24 Aug 2025</date>
12+
<priority>99</priority>
13+
14+
<discussion>
15+
<p>
16+
`std::indirect`'s `operator==
17+
<a href="https://github.com/cplusplus/papers/issues/1680#issuecomment-2646604309">intentionally</a>
18+
uses <i>Mandates</i> instead of <i>Constraints</i> to support incomplete types. However, its
19+
function signature has the following `noexcept` specification:
20+
</p>
21+
<blockquote><pre>
22+
template&lt;class U, class AA&gt;
23+
constexpr bool operator==(const indirect&amp; lhs, const indirect&lt;U, AA&gt;&amp; rhs)
24+
noexcept(noexcept(*lhs == *rhs));
25+
</pre></blockquote>
26+
<p>
27+
That is, we check whether the expression `*lhs == *rhs` throws, which unfortunately leads to
28+
the following hard error:
29+
</p>
30+
<blockquote><pre>
31+
struct Incomplete;
32+
static_assert(std::equality_comparable&lt;std::indirect&lt;Incomplete&gt;&gt;);
33+
// <span style="color:#C80000;font-weight:bold">hard error, no match for 'operator==' (operand types are 'const Incomplete' and 'const Incomplete')</span>
34+
</pre></blockquote>
35+
<p>
36+
This makes `operator==` not SFINAE-friendly for incomplete types, which defeats the purpose.
37+
<p/>
38+
Also, checking `noexcept(*lhs == *rhs)` seems insufficient because the result of `*lhs == *rhs`
39+
might still throw during conversion to `bool`.
40+
</p>
41+
</discussion>
42+
43+
<resolution>
44+
<p>
45+
This wording is relative to <paper num="N5014"/>.
46+
</p>
47+
48+
<blockquote class="note">
49+
<p>
50+
[<i>Drafting note:</i>: We introduce the exposition-only function <tt><i>FUN</i></tt> below to mimic
51+
the implicit conversion to `bool`. As a drive-by effect this helps us simplifying (and clarifying, see
52+
LWG <iref ref="408"/>) the existing <i>Mandates</i> element]
53+
</p>
54+
</blockquote>
55+
56+
<ol>
57+
58+
<li><p>Modify <sref ref="[indirect.relops]"/> as indicated:</p>
59+
60+
<blockquote>
61+
<pre>
62+
template&lt;class U, class AA&gt;
63+
constexpr bool operator==(const indirect&amp; lhs, const indirect&lt;U, AA&gt;&amp; rhs)
64+
noexcept(<del>noexcept(*lhs == *rhs)</del><ins><i>see below</i></ins>);
65+
</pre>
66+
<blockquote>
67+
<p>
68+
<ins>-?- Let <tt><i>FUN</i></tt> denote the exposition-only function</ins>
69+
</p>
70+
<blockquote><pre>
71+
<ins>bool <i>FUN</i>(bool) noexcept;</ins>
72+
</pre></blockquote>
73+
<p>
74+
-1- <i>Mandates</i>: The expression <tt><ins><i>FUN</i>(</ins>*lhs == *rhs<ins>)</ins></tt> is well-formed <del>and its result is convertible to `bool`</del>.
75+
<p/>
76+
-2- <i>Returns</i>: If `lhs` is valueless or `rhs` is valueless,
77+
`lhs.valueless_after_move() == rhs.valueless_after_move()`; otherwise `*lhs == *rhs`.
78+
<p/>
79+
<ins>-?- <i>Remarks</i>: The exception specification is equivalent to:</ins>
80+
</p>
81+
<blockquote><pre>
82+
<ins>requires (const T&amp; lhs, const U&amp; rhs) { { <i>FUN</i>(lhs == rhs) } noexcept; }</ins>
83+
</pre></blockquote>
84+
</blockquote>
85+
</blockquote>
86+
87+
</li>
88+
89+
<li><p>Modify <sref ref="[indirect.comp.with.t]"/> as indicated:</p>
90+
91+
<blockquote>
92+
<pre>
93+
template&lt;class U&gt;
94+
constexpr bool operator==(const indirect&amp; lhs, const U&amp; rhs) noexcept(<del>noexcept(*lhs == rhs)</del><ins><i>see below</i></ins>);
95+
</pre>
96+
<blockquote>
97+
<p>
98+
<ins>-?- Let <tt><i>FUN</i></tt> denote the exposition-only function</ins>
99+
</p>
100+
<blockquote><pre>
101+
<ins>bool <i>FUN</i>(bool) noexcept;</ins>
102+
</pre></blockquote>
103+
<p>
104+
-1- <i>Mandates</i>: The expression <tt><ins><i>FUN</i>(</ins>*lhs == *rhs<ins>)</ins></tt> is well-formed <del>and its result is convertible to `bool`</del>.
105+
<p/>
106+
-2- <i>Returns</i>: If `lhs` is valueless, `false`; otherwise `*lhs == rhs`.
107+
<p/>
108+
<ins>-?- <i>Remarks</i>: The exception specification is equivalent to:</ins>
109+
</p>
110+
<blockquote><pre>
111+
<ins>requires (const T&amp; lhs, const U&amp; rhs) { { <i>FUN</i>(lhs == rhs) } noexcept; }</ins>
112+
</pre></blockquote>
113+
</blockquote>
114+
</blockquote>
115+
116+
</li>
117+
118+
</ol>
119+
</resolution>
120+
121+
</issue>

0 commit comments

Comments
 (0)