Skip to content

Commit e90de8a

Browse files
committed
New issue from Peter Kasting: "std::vector::erase[_if] should be based on ranges remove"
1 parent 1fb9029 commit e90de8a

File tree

1 file changed

+80
-0
lines changed

1 file changed

+80
-0
lines changed

xml/issue4219.xml

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?xml version='1.0' encoding='utf-8' standalone='no'?>
2+
<!DOCTYPE issue SYSTEM "lwg-issue.dtd">
3+
4+
<issue num="4219" status="New">
5+
<title><tt>std::vector::erase[_if]</tt> should be based on ranges `remove`</title>
6+
<section>
7+
<sref ref="[vector.erasure]"/>
8+
</section>
9+
<submitter>Peter Kasting</submitter>
10+
<date>05 Mar 2025</date>
11+
<priority>99</priority>
12+
13+
<discussion>
14+
<p>
15+
C++20 added <tt>std::vector::erase[_if]</tt>. Per <sref ref="[vector.erasure]"/>, these are equivalent
16+
to a call to <tt>std::remove[_if]</tt> followed by an appropriate <tt>erase</tt>.
17+
<p/>
18+
This is unfortunate, because `std::remove_if` is specified (by <sref ref="[alg.remove]"/>) as invoking
19+
its predicate as `pred(*i)`, while `std::ranges::remove_if` uses the more flexible
20+
`invoke(pred, invoke(proj, *i))`. Disregarding the projection, the latter allows the use of member function
21+
pointers as predicates, while the former does not.
22+
<p/>
23+
I assume the committee intentionally did not change the non-ranges version to use `invoke` because it
24+
caused a backwards-compatibility risk. (If I am mistaken and this was an oversight, perhaps this and
25+
other non-ranges algorithms that take predicates should be updated to use invoke() to invoke them.)
26+
<p/>
27+
If that's true, though, it's perplexing why a new-to-c++20 function like `std::vector::erase_if`
28+
should suffer the same drawback.
29+
</p>
30+
</discussion>
31+
32+
<resolution>
33+
<p>
34+
This wording is relative to <paper num="N5001"/>.
35+
</p>
36+
37+
<ol>
38+
39+
<li><p>Modify <sref ref="[vector.erasure]"/> as indicated:</p>
40+
41+
<blockquote>
42+
<pre>
43+
template&lt;class T, class Allocator, class U = T&gt;
44+
constexpr typename vector&lt;T, Allocator&gt;::size_type
45+
erase(vector&lt;T, Allocator&gt;&amp; c, const U&amp; value);
46+
</pre>
47+
<blockquote>
48+
<p>
49+
-1- <i>Effects</i>: Equivalent to:
50+
</p>
51+
<blockquote><pre>
52+
auto <ins>r</ins><del>it</del> = <ins>ranges::</ins>remove(c<del>.begin(), c.end()</del>, value);
53+
<del>auto r = distance(it, c.end());</del>
54+
c.erase(<ins>r.begin()</ins><del>it</del>, <ins>r</ins><del>c</del>.end());
55+
return r<ins>.size()</ins>;
56+
</pre></blockquote>
57+
</blockquote>
58+
<pre>
59+
template&lt;class T, class Allocator, class Predicate&gt;
60+
constexpr typename vector&lt;T, Allocator&gt;::size_type
61+
erase_if(vector&lt;T, Allocator&gt;&amp; c, Predicate pred);
62+
</pre>
63+
<blockquote>
64+
<p>
65+
-2- <i>Effects</i>: Equivalent to:
66+
</p>
67+
<blockquote><pre>
68+
auto <ins>r</ins><del>it</del> = <ins>ranges::</ins>remove_if(c<del>.begin(), c.end()</del>, pred);
69+
<del>auto r = distance(it, c.end());</del>
70+
c.erase(<ins>r.begin()</ins><del>it</del>, <ins>r</ins><del>c</del>.end());
71+
return r<ins>.size()</ins>;
72+
</pre></blockquote>
73+
</blockquote>
74+
</blockquote>
75+
</li>
76+
</ol>
77+
78+
</resolution>
79+
80+
</issue>

0 commit comments

Comments
 (0)