Skip to content

Commit 69ff630

Browse files
committed
New issue from Alex Guteniev: "copy_if, remove_copy, remove_copy_if, unique_copy have too strong preconditions"
1 parent 75b40e7 commit 69ff630

File tree

1 file changed

+137
-0
lines changed

1 file changed

+137
-0
lines changed

xml/issue4262.xml

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
<?xml version='1.0' encoding='utf-8' standalone='no'?>
2+
<!DOCTYPE issue SYSTEM "lwg-issue.dtd">
3+
4+
<issue num="4262" status="New">
5+
<title>`copy_if`, `remove_copy`, `remove_copy_if`, `unique_copy` have too strong preconditions</title>
6+
<section><sref ref="[alg.copy]"/><sref ref="[alg.remove]"/><sref ref="[alg.unique]"/></section>
7+
<submitter>Alex Guteniev</submitter>
8+
<date>12 May 2025</date>
9+
<priority>99</priority>
10+
11+
<discussion>
12+
<p>
13+
<sref ref="[alg.copy]"/>/16 , <sref ref="[alg.remove]"/>/11, <sref ref="[alg.unique]"/>/8.1 all say:
14+
</p>
15+
<blockquote>
16+
<p>
17+
<i>Preconditions</i>: The ranges `[first, last)` and `[result, result + (last - first))` do not overlap.
18+
</p>
19+
</blockquote>
20+
<p>
21+
These algorithms may produce fewer elements than `(last - first)`. If this is known in advance,
22+
a smaller output range may be used, so that the precondition will not be satisfied.
23+
<p/>
24+
Example from LLVM test suite
25+
(<a href="https://github.com/llvm/llvm-project/blob/79210feb2993ff9a79ef11f8a7016a527d4fcf22/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_if.pass.cpp#L160-L162">
26+
/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_if.pass.cpp</a>):
27+
</p>
28+
<blockquote><pre>
29+
std::array&lt;S, 4&gt; in = {{{4, 2}, {1, 3}, {3, 4}, {3, 5}}};
30+
std::array&lt;S, 2&gt; out;
31+
auto ret = std::ranges::copy_if(in.begin(), in.end(), out.begin(), [](int i) { return i == 3; }, &amp;S::val);
32+
</pre></blockquote>
33+
<p>
34+
I think there should be a weaker precondition, like <sref ref="[alg.copy]"/>/2:
35+
</p>
36+
<blockquote>
37+
<p>
38+
<i>Preconditions</i>: `result` is not in the range `[first, last)`.
39+
</p>
40+
</blockquote>
41+
</discussion>
42+
43+
<resolution>
44+
<p>
45+
This wording is relative to <paper num="N5008"/>.
46+
</p>
47+
<ol>
48+
49+
<li><p>Modify <sref ref="[alg.copy]"/> as indicated:</p>
50+
51+
<blockquote>
52+
<pre>
53+
template&lt;class InputIterator, class OutputIterator, class Predicate&gt;
54+
constexpr OutputIterator copy_if(InputIterator first, InputIterator last,
55+
OutputIterator result, Predicate pred);
56+
[&hellip;]
57+
template&lt;input_range R, weakly_incrementable O, class Proj = identity,
58+
indirect_unary_predicate&lt;projected&lt;iterator_t&lt;R&gt;, Proj&gt;&gt; Pred&gt;
59+
requires indirectly_copyable&lt;iterator_t&lt;R&gt;, O&gt;
60+
constexpr ranges::copy_if_result&lt;borrowed_iterator_t&lt;R&gt;, O&gt;
61+
ranges::copy_if(R&amp;&amp; r, O result, Pred pred, Proj proj = {});
62+
</pre>
63+
<blockquote>
64+
<p>
65+
-15- Let <tt><i>E</i></tt> be: [&hellip;]
66+
<p/>
67+
-16 <i>Preconditions</i>: <ins>`result` is not in the range `[first, last)`</ins><del>The ranges `[first, last)` and `[result, result + (last - first))` do not overlap</del>.
68+
</p>
69+
</blockquote>
70+
</blockquote>
71+
</li>
72+
73+
<li><p>Modify <sref ref="[alg.remove]"/> as indicated:</p>
74+
75+
<blockquote>
76+
<pre>
77+
template&lt;class InputIterator, class OutputIterator,
78+
class T = iterator_traits&lt;InputIterator&gt;::value_type>
79+
constexpr OutputIterator
80+
remove_copy(InputIterator first, InputIterator last,
81+
OutputIterator result, const T&amp; value);
82+
[&hellip;]
83+
template&lt;input_range R, weakly_incrementable O, class Proj = identity,
84+
indirect_unary_predicate&lt;projected&lt;iterator_t&lt;R&gt;, Proj&gt;&gt; Pred&gt;
85+
requires indirectly_copyable&lt;iterator_t&lt;R&gt;, O&gt;
86+
constexpr ranges::remove_copy_if_result&lt;borrowed_iterator_t&lt;R&gt;, O&gt;
87+
ranges::remove_copy_if(R&amp;&amp; r, O result, Pred pred, Proj proj = {});
88+
</pre>
89+
<blockquote>
90+
<p>
91+
-8- Let <tt><i>E</i></tt> be [&hellip;]
92+
<p/>
93+
[&hellip;]
94+
<p/>
95+
-11 <i>Preconditions</i>: <ins>`result` is not in the range `[first, last)`</ins><del>The ranges `[first, last)` and `[result, result + (last - first))` do not overlap</del>.
96+
</p>
97+
</blockquote>
98+
</blockquote>
99+
</li>
100+
101+
<li><p>Modify <sref ref="[alg.unique]"/> as indicated:</p>
102+
103+
<blockquote>
104+
<pre>
105+
template&lt;class InputIterator, class OutputIterator&gt;
106+
constexpr OutputIterator
107+
unique_copy(InputIterator first, InputIterator last,
108+
OutputIterator result);
109+
[&hellip;]
110+
template&lt;input_range R, weakly_incrementable O, class Proj = identity,
111+
indirect_equivalence_relation&lt;projected&lt;iterator_t&lt;R&gt;, Proj&gt;&gt; C = ranges::equal_to&gt;
112+
requires indirectly_copyable&lt;iterator_t&lt;R&gt;, O&gt; &amp;&amp;
113+
(forward_iterator&lt;iterator_t&lt;R&gt;&gt; ||
114+
(input_iterator&lt;O&gt; &amp;&amp; same_as&lt;range_value_t&lt;R&gt;, iter_value_t&lt;O&gt;&gt;) ||
115+
indirectly_copyable_storable&lt;iterator_t&lt;R&gt;, O&gt;)
116+
constexpr ranges::unique_copy_result&lt;borrowed_iterator_t&lt;R&gt;, O&gt;
117+
ranges::unique_copy(R&amp;&amp; r, O result, C comp = {}, Proj proj = {});
118+
</pre>
119+
<blockquote>
120+
<p>
121+
-6- Let `pred` be [&hellip;]
122+
<p/>
123+
-7- <i>Mandates</i>: [&hellip;]
124+
<p/>
125+
-8 <i>Preconditions</i>:
126+
</p>
127+
<ol style="list-style-type: none">
128+
<li><p>(8.1) &mdash; <ins><ins>`result` is not in the range `[first, last)`</ins></ins><del>The ranges `[first, last)` and `[result, result + (last - first))` do not overlap</del>.</p></li>
129+
<li><p>(8.2) &mdash; [&hellip;]</p></li>
130+
</ol>
131+
</blockquote>
132+
</blockquote>
133+
</li>
134+
</ol>
135+
</resolution>
136+
137+
</issue>

0 commit comments

Comments
 (0)