Skip to content

Commit ffaecf3

Browse files
committed
New issue from Jonathan: experimental::observer_ptr should have more constexpr
1 parent 22cbd92 commit ffaecf3

File tree

1 file changed

+220
-0
lines changed

1 file changed

+220
-0
lines changed

xml/issue4295.xml

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
<?xml version='1.0' encoding='utf-8' standalone='no'?>
2+
<!DOCTYPE issue SYSTEM "lwg-issue.dtd">
3+
4+
<issue num="4295" status="New">
5+
<title>[fund.ts.v3] `experimental::observer_ptr` should have more constexpr</title>
6+
<section><sref ref="[memory.observer.ptr.special]"/></section>
7+
<submitter>Jonathan Wakely</submitter>
8+
<date>14 Jul 2025</date>
9+
<priority>99</priority>
10+
11+
<discussion>
12+
<p>
13+
In the Library Fundamentals TS, the `swap` overload, `make_observer_ptr`
14+
function, and comparisons for `observer_ptr` could be constexpr, but are not.
15+
The member `swap` is already constexpr in the TS, and the non-member `swap`
16+
is constexpr in libc++ but not the comparisons. The proposed resolution has
17+
been implemented and tested in libstdc++.
18+
</p>
19+
<p>
20+
If we ever rebase the TS on a new C++ standard the comparisons should all be
21+
updated like so:
22+
</p>
23+
24+
<blockquote>
25+
<pre><code>
26+
template &lt;class W1, class W2&gt;
27+
<ins>constexpr</ins> bool operator==(observer_ptr&lt;W1&gt; p1, observer_ptr&lt;W2&gt; p2);
28+
</code></pre>
29+
<blockquote>
30+
<i>Returns</i>: `p1.get() == p2.get()`.
31+
</blockquote>
32+
33+
<pre><code><del>bool operator!=(...);</del></code></pre>
34+
35+
<pre><code>
36+
template &lt;class W&gt;
37+
<ins>constexpr</ins> bool operator==(observer_ptr&lt;W&gt; p, nullptr_t) noexcept;
38+
<del>bool operator==(...);</del>
39+
</code></pre>
40+
<blockquote>
41+
<i>Returns</i>: `not p`.
42+
</blockquote>
43+
44+
<pre><code><del>bool operator!=(...);
45+
bool operator!=(...);</del></code></pre>
46+
47+
<pre><code>
48+
template &lt;class W1, class W2&gt;
49+
<ins>constexpr</ins> bool operator&lt;<ins>=&gt;</ins>(observer_ptr&lt;W1&gt; p1, observer_ptr&lt;W2&gt; p2);
50+
</code></pre>
51+
<blockquote>
52+
<i>Returns</i>:
53+
<code><del>less&lt;W3&gt;</del><ins>compare_three_way</ins>()(p1.get(), p2.get())</code>,
54+
where `W3` is the composite pointer type (C++20 §7) of `W1*` and `W2*`.
55+
</blockquote>
56+
57+
<pre><code><del>bool operator&gt;(...);
58+
bool operator&lt;=(...);
59+
bool operator&gt;=(...);</del></code></pre>
60+
</blockquote>
61+
62+
</discussion>
63+
64+
<resolution>
65+
<p>
66+
This wording is relative to <paper num="N4939"/>.
67+
</p>
68+
69+
<ol>
70+
<li>
71+
Modify <sref ref="[memory.syn]"/> as indicated:
72+
<blockquote>
73+
<pre><code>
74+
#include &lt;memory&gt;
75+
76+
namespace std {
77+
namespace experimental::inline fundamentals_v3 {
78+
79+
<i>// 8.2, Non-owning (observer) pointers</i>
80+
template &lt;class W&gt; class observer_ptr;
81+
82+
<i>// 8.2.6, observer_ptr specialized algorithms</i>
83+
template &lt;class W&gt;
84+
<ins>constexpr</ins> void swap(observer_ptr&lt;W&gt;&amp;, observer_ptr&lt;W&gt;&amp;) noexcept;
85+
template &lt;class W&gt;
86+
<ins>constexpr</ins> observer_ptr&lt;W&gt; make_observer(W*) noexcept;
87+
<i>// (in)equality operators</i>
88+
template &lt;class W1, class W2&gt;
89+
<ins>constexpr</ins> bool operator==(observer_ptr&lt;W1&gt;, observer_ptr&lt;W2&gt;);
90+
91+
template &lt;class W1, class W2&gt;
92+
<ins>constexpr</ins> bool operator!=(observer_ptr&lt;W1&gt;, observer_ptr&lt;W2&gt;);
93+
template &lt;class W&gt;
94+
<ins>constexpr</ins> bool operator==(observer_ptr&lt;W&gt;, nullptr_t) noexcept;
95+
template &lt;class W&gt;
96+
<ins>constexpr</ins> bool operator!=(observer_ptr&lt;W&gt;, nullptr_t) noexcept;
97+
template &lt;class W&gt;
98+
<ins>constexpr</ins> bool operator==(nullptr_t, observer_ptr&lt;W&gt;) noexcept;
99+
template &lt;class W&gt;
100+
<ins>constexpr</ins> bool operator!=(nullptr_t, observer_ptr&lt;W&gt;) noexcept;
101+
<i>// ordering operators</i>
102+
template &lt;class W1, class W2&gt;
103+
<ins>constexpr</ins> bool operator&lt;(observer_ptr&lt;W1&gt;, observer_ptr&lt;W2&gt;);
104+
template &lt;class W1, class W2&gt;
105+
<ins>constexpr</ins> bool operator&gt;(observer_ptr&lt;W1&gt;, observer_ptr&lt;W2&gt;);
106+
template &lt;class W1, class W2&gt;
107+
<ins>constexpr</ins> bool operator&lt;=(observer_ptr&lt;W1&gt;, observer_ptr&lt;W2&gt;);
108+
template &lt;class W1, class W2&gt;
109+
<ins>constexpr</ins> bool operator&gt;=(observer_ptr&lt;W1&gt;, observer_ptr&lt;W2&gt;);
110+
111+
} <i>// namespace experimental::inline fundamentals_v3</i>
112+
113+
<i>// 8.2.7, observer_ptr hash support</i>
114+
template &lt;class T&gt; struct hash;
115+
template &lt;class T&gt; struct hash&lt;experimental::observer_ptr&lt;T&gt;&gt;;
116+
117+
} <i>// namespace std</i>
118+
</code></pre>
119+
</blockquote>
120+
</li>
121+
122+
<li>
123+
Modify <sref ref="[memory.observer.ptr.special]"/> as indicated:
124+
<blockquote>
125+
126+
127+
<pre><code>
128+
template &lt;class W&gt;
129+
<ins>constexpr</ins> void swap(observer_ptr&lt;W&gt;&amp; p1, observer_ptr&lt;W&gt;&amp; p2) noexcept;
130+
</code></pre>
131+
<blockquote>
132+
-2- <i>Effects</i>: `p1.swap(p2)`.
133+
</blockquote>
134+
135+
<pre><code>
136+
template &lt;class W&gt; <ins>constexpr</ins> observer_ptr&lt;W&gt; make_observer(W* p) noexcept;
137+
</code></pre>
138+
<blockquote>
139+
-4- <i>Returns</i>: <code>observer_ptr&lt;W&gt;{p}</code>.
140+
</blockquote>
141+
142+
143+
<pre><code>
144+
template &lt;class W1, class W2&gt;
145+
<ins>constexpr</ins> bool operator==(observer_ptr&lt;W1&gt; p1, observer_ptr&lt;W2&gt; p2);
146+
</code></pre>
147+
<blockquote>
148+
-6- <i>Returns</i>: `p1.get() == p2.get()`.
149+
</blockquote>
150+
151+
<pre><code>
152+
template &lt;class W1, class W2&gt;
153+
<ins>constexpr</ins> bool operator!=(observer_ptr&lt;W1&gt; p1, observer_ptr&lt;W2&gt; p2);
154+
</code></pre>
155+
<blockquote>
156+
-8- <i>Returns</i>: `not (p1 == p2)`.
157+
</blockquote>
158+
159+
<pre><code>
160+
template &lt;class W&gt;
161+
<ins>constexpr</ins> bool operator==(observer_ptr&lt;W&gt; p, nullptr_t) noexcept;
162+
template &lt;class W&gt;
163+
<ins>constexpr</ins> bool operator==(nullptr_t, observer_ptr&lt;W&gt; p) noexcept;
164+
</code></pre>
165+
<blockquote>
166+
-10- <i>Returns</i>: `not p`.
167+
</blockquote>
168+
169+
<pre><code>
170+
template &lt;class W&gt;
171+
<ins>constexpr</ins> bool operator!=(observer_ptr&lt;W&gt; p, nullptr_t) noexcept;
172+
template &lt;class W&gt;
173+
<ins>constexpr</ins> bool operator!=(nullptr_t, observer_ptr&lt;W&gt; p) noexcept;
174+
</code></pre>
175+
<blockquote>
176+
-12- <i>Returns</i>: `(bool)p`.
177+
</blockquote>
178+
179+
<pre><code>
180+
template &lt;class W1, class W2&gt;
181+
<ins>constexpr</ins> bool operator&lt;(observer_ptr&lt;W1&gt; p1, observer_ptr&lt;W2&gt; p2);
182+
</code></pre>
183+
<blockquote>
184+
-14- <i>Returns</i>:
185+
<code>less&lt;W3&gt;()(p1.get(), p2.get())</code>,
186+
where `W3` is the composite pointer type (C++20 §7) of `W1*` and `W2*`.
187+
</blockquote>
188+
189+
<pre><code>
190+
template &lt;class W1, class W2&gt;
191+
<ins>constexpr</ins> bool operator&gt;(observer_ptr&lt;W1&gt; p1, observer_ptr&lt;W2&gt; p2);
192+
</code></pre>
193+
<blockquote>
194+
-16- <i>Returns</i>: <code>p2 &lt; p1</code>.
195+
</blockquote>
196+
197+
<pre><code>
198+
template &lt;class W1, class W2&gt;
199+
<ins>constexpr</ins> bool operator&lt;=(observer_ptr&lt;W1&gt; p1, observer_ptr&lt;W2&gt; p2);
200+
</code></pre>
201+
<blockquote>
202+
-16- <i>Returns</i>: <code>not p2 &lt; p1</code>.
203+
</blockquote>
204+
205+
<pre><code>
206+
template &lt;class W1, class W2&gt;
207+
<ins>constexpr</ins> bool operator&gt;=(observer_ptr&lt;W1&gt; p1, observer_ptr&lt;W2&gt; p2);
208+
</code></pre>
209+
<blockquote>
210+
-16- <i>Returns</i>: <code>not p1 &lt; p2</code>.
211+
</blockquote>
212+
213+
214+
</blockquote>
215+
</li>
216+
</ol>
217+
218+
</resolution>
219+
220+
</issue>

0 commit comments

Comments
 (0)