Skip to content

Commit da0c7bf

Browse files
committed
New issue from Jiang An: "std::decay_t in the specification of ranges::distance is problematic"
1 parent e9ae21c commit da0c7bf

File tree

1 file changed

+68
-12
lines changed

1 file changed

+68
-12
lines changed

xml/issue4303.xml

Lines changed: 68 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,86 @@
22
<!DOCTYPE issue SYSTEM "lwg-issue.dtd">
33

44
<issue num="4303" status="New">
5-
<title>Interaction between LWG 2259 and <i>Constraints</i> of member functions</title>
6-
<section><sref ref="[member.functions]"/></section>
5+
<title>`std::decay_t` in the specification of `ranges::distance` is problematic</title>
6+
<section><sref ref="[range.iter.op.distance]"/></section>
77
<submitter>Jiang An</submitter>
88
<date>24 Jul 2025</date>
99
<priority>99</priority>
1010

1111
<discussion>
1212
<p>
13-
<sref ref="[member.functions]"/>/2 seems to allow that even when the constraints are not met,
14-
such a default constructor can be selected, because no restriction is imposed when no overload
15-
is originally selected. Per the discussion in LWG <iref ref="2563"/> (closed as NAD), it even
16-
seems to allow the implementation to add a default constructor when there's originally none.
13+
This is discovered when implementing the resolution LWG <iref ref="4242"/>.
14+
Per LWG <iref ref="4242"/>, it is intended to allow `ranges::distance` to handle
15+
`volatile`-qualified iterator values.
16+
However, the uses of `decay_t` (established per LWG <iref ref="3664"/>) are still problematic,
17+
because when <tt>sized_sentinel_for&lt;S, decay_t&lt;I&gt;&gt;</tt> is modeled, there's no
18+
semantic or syntactic requirement that `S` shall work with volatile-qualified `I`.
1719
<p/>
18-
However, we're constraining some member functions, e.g. default constructors of `unique_ptr`,
19-
`tuple`, and `variant`. Allowance of more permissive overload sets of constructors effectively
20-
renders the <i>Constraints</i> meaningless, because even if the implementation doesn't constrain
21-
the default constructors at all, it can still satisfy the restriction in
22-
<sref ref="[member.functions]"/>/2 since LWG <iref ref="2259"/>.
20+
If we implement the constraint as is, there will still be some underconstrained cases. E.g.
21+
When the `operator==` or `operator-` intendedly rejects volatile-qualified iterators. And
22+
even when they accept volatile-qualified iterators, the additional semantic requirements
23+
imposed by <tt>sized_sentinel_for&lt;S, decay_t&lt;I&gt;&gt;</tt> are still undesired.
2324
<p/>
24-
Perhaps some wording change is necessary to guarantee the <i>Constraints</i> of member functions to be meaningful.
25+
I think we should only decay arrays and keep `volatile` for non-array arguments.
2526
</p>
2627
</discussion>
2728

2829
<resolution>
30+
<p>
31+
This wording is relative to this
32+
<a href="https://github.com/cplusplus/draft/actions/runs/16433597877/artifacts/3583518547">CD preview draft</a>.
33+
</p>
34+
35+
<ol>
36+
37+
<li><p>Modify <sref ref="[iterator.synopsis]"/>, header <tt>&lt;iterator&gt;</tt> synopsis, as indicated:</p>
38+
39+
<blockquote>
40+
<pre>
41+
[&hellip;]
42+
namespace std: {
43+
[&hellip;]
44+
// <i><sref ref="[range.iter.op.distance]"/>, ranges::distance</i>
45+
46+
<ins>template&lt;class T&gt;
47+
using <i>distance-iterator-t</i> = // <i>exposition only</i>
48+
conditional_t&lt;is_array_v&lt;remove_reference_t&lt;T&gt;&gt;,
49+
decay_t&lt;T&gt;, remove_const_t&lt;remove_reference_t&lt;T&gt;&gt;&gt;;
50+
</ins>
51+
template&lt;class I, sentinel_for&lt;I&gt; S&gt;
52+
requires (!sized_sentinel_for&lt;S, I&gt;)
53+
constexpr iter_difference_t&lt;I&gt; distance(I first, S last); // <i>freestanding</i>
54+
template&lt;class I, sized_sentinel_for&lt;<del>decay_t</del><ins><i>distance-iterator-t</i></ins>&lt;I&gt;&gt; S&gt;
55+
constexpr iter_difference_t&lt;<del>decay_t</del><ins><i>distance-iterator-t</i></ins>&lt;I&gt;&gt; distance(I&amp;&amp; first, S last); // <i>freestanding</i>
56+
template&lt;range R&gt;
57+
constexpr range_difference_t&lt;R&gt; distance(R&amp;&amp; r); // <i>freestanding</i>
58+
[&hellip;]
59+
}
60+
</pre>
61+
</blockquote>
62+
</li>
63+
64+
<li><p>Modify <sref ref="[range.iter.op.distance]"/> as indicated:</p>
65+
66+
<blockquote>
67+
<pre>
68+
template&lt;class I, sized_sentinel_for&lt;<del>decay_t</del><ins><i>distance-iterator-t</i></ins>&lt;I&gt;&gt; S&gt;
69+
constexpr iter_difference_t&lt;<del>decay_t</del><ins><i>distance-iterator-t</i></ins>&lt;I&gt;&gt; distance(I&amp;&amp; first, S last);
70+
</pre>
71+
<blockquote>
72+
<p>
73+
-3- <i>Effects</i>: Equivalent to:
74+
</p>
75+
<blockquote><pre>
76+
if constexpr (!is_array_v&lt;remove_reference_t&lt;I&gt;&gt;)
77+
return last - first;
78+
else
79+
return last - static_cast&lt;decay_t&lt;I&gt;&gt;(first);
80+
</pre></blockquote>
81+
</blockquote>
82+
</blockquote>
83+
</li>
84+
</ol>
2985
</resolution>
3086

3187
</issue>

0 commit comments

Comments
 (0)