|
2 | 2 | <!DOCTYPE issue SYSTEM "lwg-issue.dtd"> |
3 | 3 |
|
4 | 4 | <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> |
7 | 7 | <submitter>Jiang An</submitter> |
8 | 8 | <date>24 Jul 2025</date> |
9 | 9 | <priority>99</priority> |
10 | 10 |
|
11 | 11 | <discussion> |
12 | 12 | <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<S, decay_t<I>></tt> is modeled, there's no |
| 18 | +semantic or syntactic requirement that `S` shall work with volatile-qualified `I`. |
17 | 19 | <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<S, decay_t<I>></tt> are still undesired. |
23 | 24 | <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. |
25 | 26 | </p> |
26 | 27 | </discussion> |
27 | 28 |
|
28 | 29 | <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><iterator></tt> synopsis, as indicated:</p> |
| 38 | + |
| 39 | +<blockquote> |
| 40 | +<pre> |
| 41 | +[…] |
| 42 | +namespace std: { |
| 43 | + […] |
| 44 | + // <i><sref ref="[range.iter.op.distance]"/>, ranges::distance</i> |
| 45 | + |
| 46 | + <ins>template<class T> |
| 47 | + using <i>distance-iterator-t</i> = // <i>exposition only</i> |
| 48 | + conditional_t<is_array_v<remove_reference_t<T>>, |
| 49 | + decay_t<T>, remove_const_t<remove_reference_t<T>>>; |
| 50 | +</ins> |
| 51 | + template<class I, sentinel_for<I> S> |
| 52 | + requires (!sized_sentinel_for<S, I>) |
| 53 | + constexpr iter_difference_t<I> distance(I first, S last); // <i>freestanding</i> |
| 54 | + template<class I, sized_sentinel_for<<del>decay_t</del><ins><i>distance-iterator-t</i></ins><I>> S> |
| 55 | + constexpr iter_difference_t<<del>decay_t</del><ins><i>distance-iterator-t</i></ins><I>> distance(I&& first, S last); // <i>freestanding</i> |
| 56 | + template<range R> |
| 57 | + constexpr range_difference_t<R> distance(R&& r); // <i>freestanding</i> |
| 58 | + […] |
| 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<class I, sized_sentinel_for<<del>decay_t</del><ins><i>distance-iterator-t</i></ins><I>> S> |
| 69 | + constexpr iter_difference_t<<del>decay_t</del><ins><i>distance-iterator-t</i></ins><I>> distance(I&& 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<remove_reference_t<I>>) |
| 77 | + return last - first; |
| 78 | +else |
| 79 | + return last - static_cast<decay_t<I>>(first); |
| 80 | +</pre></blockquote> |
| 81 | +</blockquote> |
| 82 | +</blockquote> |
| 83 | +</li> |
| 84 | +</ol> |
29 | 85 | </resolution> |
30 | 86 |
|
31 | 87 | </issue> |
0 commit comments