Skip to content

Commit 337bd66

Browse files
committed
New issue from Jiang An: "std::ranges::to with union return type"
1 parent f2a4b28 commit 337bd66

File tree

1 file changed

+127
-0
lines changed

1 file changed

+127
-0
lines changed

xml/issue4229.xml

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
<?xml version='1.0' encoding='utf-8' standalone='no'?>
2+
<!DOCTYPE issue SYSTEM "lwg-issue.dtd">
3+
4+
<issue num="4229" status="New">
5+
<title>`std::ranges::to` with union return type</title>
6+
<section>
7+
<sref ref="[range.utility.conv.to]"/><sref ref="[range.utility.conv.adaptors]"/>
8+
</section>
9+
<submitter>Jiang An</submitter>
10+
<date>20 Mar 2025</date>
11+
<priority>99</priority>
12+
13+
<discussion>
14+
<p>
15+
LWG <iref ref="3847"/> made `std::ranges::to` require the return type (or the target type for the overload
16+
returning range adaptor closure object) to be a <i>cv</i>-unqualified class type. Although the term
17+
"class type" in core language specification also covers union types, implementations (libstdc++ and MSVC STL)
18+
tend to implement this part of the <i>Mandates</i> only with `std::is_class_v`, which rejects union types.
19+
<p/>
20+
E.g. the following program is rejected by libstdc++ and MSVC STL
21+
(<a href="https://godbolt.org/z/MnsY4Tzen">https://godbolt.org/z/MnsY4Tzen</a>):
22+
</p>
23+
<blockquote><pre>
24+
#include &lt;memory&gt;
25+
#include &lt;ranges&gt;
26+
#include &lt;type_traits&gt;
27+
#include &lt;utility&gt;
28+
#include &lt;vector&gt;
29+
30+
template&lt;class T, class A = std::allocator&lt;T&gt;&gt;
31+
union weird_vector {
32+
std::vector&lt;T, A&gt; vec_;
33+
34+
constexpr weird_vector() : vec_() {}
35+
constexpr weird_vector(const weird_vector&amp; other) : vec_(other.vec_) {}
36+
constexpr weird_vector(weird_vector&amp;&amp; other) noexcept : vec_(std::move(other.vec_)) {}
37+
38+
template&lt;class U&gt;
39+
requires (!std::same_as&lt;std::remove_cvref_t&lt;U&gt;, weird_vector&gt;) &amp;&amp;
40+
(!std::same_as&lt;std::remove_cvref_t&lt;U&gt;, std::vector&lt;T, A&gt;&gt;) &amp;&amp;
41+
requires(U&amp;&amp; u) { std::vector&lt;T, A&gt;(std::forward&lt;U&gt;(u)); }
42+
constexpr explicit weird_vector(U&amp;&amp; u) : vec_(std::forward&lt;U&gt;(u)) {}
43+
44+
template&lt;class T1, class T2, class... Ts&gt;
45+
requires requires(T1&amp;&amp; t1, T2&amp;&amp; t2, Ts&amp;&amp;... ts) {
46+
std::vector&lt;T, A&gt;(std::forward&lt;T1&gt;(t1), std::forward&lt;T2&gt;(t2), std::forward&lt;Ts&gt;(ts)...);
47+
}
48+
constexpr weird_vector(T1&amp;&amp; t1, T2&amp;&amp; t2, Ts&amp;&amp;... ts)
49+
: vec_(std::forward&lt;T1&gt;(t1), std::forward&lt;T2&gt;(t2), std::forward&lt;Ts&gt;(ts)...) {}
50+
51+
constexpr weird_vector&amp; operator=(const weird_vector&amp; other) {
52+
vec_ = other.vec_;
53+
return *this;
54+
}
55+
constexpr weird_vector&amp; operator=(weird_vector&amp;&amp; other)
56+
noexcept(std::is_nothrow_move_assignable_v&lt;std::vector&lt;T, A&gt;&gt;) {
57+
vec_ = std::move(other.vec_);
58+
return *this;
59+
}
60+
61+
constexpr ~weird_vector() {
62+
vec_.~vector();
63+
}
64+
};
65+
66+
int main() {
67+
int arr[]{42, 1729};
68+
auto v [[maybe_unused]] = std::ranges::to&lt;weird_vector&lt;int&gt;&gt;(arr);
69+
}
70+
</pre></blockquote>
71+
<p>
72+
Although libc++ currently accepts this example, the acceptance seems to be a bug, because libc++ hasn't
73+
implemented the "class" part in the <i>Mandates</i> at all
74+
(<a href="https://github.com/llvm/llvm-project/issues/132133">llvm/llvm-project#132133</a>).
75+
<p/>
76+
It's unclear whether union types were intended to be accepted. Perhaps we should follow implementations'
77+
choices and reject them.
78+
</p>
79+
</discussion>
80+
81+
<resolution>
82+
<p>
83+
This wording is relative to <paper num="N5008"/>.
84+
</p>
85+
86+
<ol>
87+
88+
<li><p>Modify <sref ref="[range.utility.conv.to]"/> as indicated:</p>
89+
90+
<blockquote>
91+
<pre>
92+
template&lt;class C, input_range R, class... Args&gt; requires (!view&lt;C&gt;)
93+
constexpr C to(R&amp;&amp; r, Args&amp;&amp;... args);
94+
</pre>
95+
<blockquote>
96+
<p>
97+
-1- <i>Mandates</i>: `C` is a cv-unqualified <ins>non-union</ins> class type.
98+
<p/>
99+
[&hellip;]
100+
</p>
101+
</blockquote>
102+
</blockquote>
103+
</li>
104+
105+
<li><p>Modify <sref ref="[range.utility.conv.adaptors]"/> as indicated:</p>
106+
107+
<blockquote>
108+
<pre>
109+
template&lt;class C, class... Args&gt; requires (!view&lt;C&gt;)
110+
constexpr auto to(Args&amp;&amp;... args);
111+
template&lt;template&lt;class...&gt; class C, class... Args&gt;
112+
constexpr auto to(Args&amp;&amp;... args);
113+
</pre>
114+
<blockquote>
115+
<p>
116+
-1- <i>Mandates</i>: For the first overload, `C` is a cv-unqualified <ins>non-union</ins> class type.
117+
<p/>
118+
[&hellip;]
119+
</p>
120+
</blockquote>
121+
</blockquote>
122+
</li>
123+
124+
</ol>
125+
</resolution>
126+
127+
</issue>

0 commit comments

Comments
 (0)