Skip to content

Commit 4c5cbff

Browse files
committed
New issue from Hewill: "join_view incorrectly stores inner range"
1 parent e90de8a commit 4c5cbff

File tree

1 file changed

+103
-0
lines changed

1 file changed

+103
-0
lines changed

xml/issue4220.xml

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?xml version='1.0' encoding='utf-8' standalone='no'?>
2+
<!DOCTYPE issue SYSTEM "lwg-issue.dtd">
3+
4+
<issue num="4220" status="New">
5+
<title><code>join_view</code> incorrectly stores inner range</title>
6+
<section>
7+
<sref ref="[range.join.view]"/><sref ref="[range.join.with.view]"/>
8+
</section>
9+
<submitter>Hewill Kang</submitter>
10+
<date>06 Mar 2025</date>
11+
<priority>99</priority>
12+
13+
<discussion>
14+
<p>
15+
When the inner range is a prvalue, <code>join_view</code> removes its <i>cv</i>-qualifiers
16+
and stores it in the <code><i>propagating-cache</i></code>, which is not quite right as the inner range may
17+
only be const-iterable (<a href="https://godbolt.org/z/qY1bhExzG">demo</a>):
18+
</p>
19+
<blockquote><pre>
20+
#include &lt;ranges&gt;
21+
22+
struct R {
23+
int* begin() = delete;
24+
int* end() = delete;
25+
const int* begin() const;
26+
const int* end() const;
27+
};
28+
29+
int main() {
30+
auto r = std::views::iota(0, 5)
31+
| std::views::transform([](int) -> const R { return {}; })
32+
| std::views::join;
33+
auto b = r.begin(); // <span style="color:red;font-weight:bolder">hard error</span>
34+
}
35+
</pre></blockquote>
36+
<p>
37+
The proposed resolution preserves the inner range's original qualifiers, which is consistent with how
38+
<code>cache_latest_view</code> stores the reference when it is a prvalue.
39+
The same goes for <code>join_with_view</code>.
40+
</p>
41+
</discussion>
42+
43+
<resolution>
44+
<p>
45+
This wording is relative to <paper num="N5001"/>.
46+
</p>
47+
48+
<ol>
49+
50+
<li><p>Modify <sref ref="[range.join.view]"/> as indicated:</p>
51+
52+
<blockquote>
53+
<pre>
54+
namespace std::ranges {
55+
template&lt;input_range V&gt;
56+
requires view&lt;V&gt; &amp;&amp; input_range&lt;range_reference_t&lt;V&gt;&gt;&gt;
57+
class join_view : public view_interface&lt;join_view&lt;V&gt;&gt; {
58+
private:
59+
using <i>InnerRng</i> = range_reference_t&lt;V&gt;; // <i>exposition only</i>
60+
[&hellip;]
61+
<i>non-propagating-cache</i>&lt;<del>remove_cv_t&lt;</del><i>InnerRng</i><del>&gt;</del>&gt; <i>inner_</i>; // <i>exposition only, present only</i>
62+
// <i>if is_reference_v&lt;<i>InnerRng</i>&gt; is false</i>
63+
64+
public:
65+
[&hellip;]
66+
};
67+
[&hellip;]
68+
}
69+
</pre>
70+
</blockquote>
71+
</li>
72+
73+
<li><p>Modify <sref ref="[range.join.with.view]"/> as indicated:</p>
74+
75+
<blockquote>
76+
<pre>
77+
namespace std::ranges {
78+
[&hellip;]
79+
template&lt;input_range V, forward_range Pattern&gt;
80+
requires view&lt;V&gt; &amp;&amp; input_range&lt;range_reference_t&lt;V&gt;&gt;
81+
&amp;&amp; view&lt;Pattern&gt;
82+
&amp;&amp; <i>concatable</i>&lt;range_reference_t&lt;V&gt;, Pattern&gt;
83+
class join_with_view : public view_interface&lt;join_with_view&lt;V, Pattern&gt;&gt; {
84+
using <i>InnerRng</i> = range_reference_t&lt;V&gt;; // <i>exposition only</i>
85+
[&hellip;]
86+
<i>non-propagating-cache</i>&lt;<del>remove_cv_t&lt;</del><i>InnerRng</i><del>&gt;</del>&gt; <i>inner_</i>; // <i>exposition only, present only</i>
87+
// <i>if is_reference_v&lt;<i>InnerRng</i>&gt; is false</i>
88+
89+
[&hellip;]
90+
public:
91+
[&hellip;]
92+
};
93+
[&hellip;]
94+
}
95+
96+
</pre>
97+
</blockquote>
98+
</li>
99+
</ol>
100+
101+
</resolution>
102+
103+
</issue>

0 commit comments

Comments
 (0)