问题
We can erase one element/ entry from a container by the popular erase–remove idiom. However, many of us would have encountered some problems while applying this idiom:
one can easily get into the pitfall of typos like
c.erase(std::remove_if(c.begin(), c.end(), pred)); // , c.end() //---> missing here
or
c.erase((std::remove_if(c.begin(), c.end(), pred), c.end())) // ^^ ^^ // extra () makes it pass only c.end() to the c.erase
- It even follows the wrong semantics for containers like
std::list
by not selecting its own member std::list::remove_if() for the idiom. - Thirdly, using
std::remove_if
does not work for associative containers.
Do we have anything generalized and less typo-prone than std::erase-std::remove_if
or something like std::erase_if
within the scope of c++17, or will there be such a utility in c++20?
回答1:
Not in the scope of c++17, but c++20 onwards!
Yes. The proposal of consistent container erasure has been mentioned in n4009 paper and finally adopted in C++20 standard as std::erase_if which is a non-member function for each containers.
This ensures a uniform container erasure semantics for std::basic_string
and all standard containers, except std::array
(as it has the fixed-size).
This means that the boilerplate code
container.erase(
std::remove_if(
container.begin(), container.end(),
[](const auto& element) ->bool { return /* condition */; }),
vec.end());
will simply melt down to a generalized form of
std::erase_if(container, [](const auto& element) ->bool { return /* condition */; });
Secondly, this uniform syntax selects the proper semantics for each container. This means
For sequence containers like std::vector, std::deque and for std::std::basic_string, it will be equivalent to
container.erase( std::remove_if(container.begin(), container.end(), unaryPredicate) , container.end() );
For sequence containers std::forward_list and std::list, it will be equivalent to
container.remove_if(unaryPredicate);
For ordered associative containers(i.e. std::set, std::map, std::multiset and std::multimap) and unordered associative containers(i.e. std::unordered_set, std::unordered_map, std::unordered_multiset and std::unordered_multimap), the
std::erase_if
is equivalent tofor (auto i = container.begin(), last = container.end(); i != last; ) { if (unaryPredicate(*i)) { i = container.erase(i); } else { ++i; } }
In addition to that, the standard also added std::erase
for sequence containers of the form
std::erase(container, value_to_be_removed);
来源:https://stackoverflow.com/questions/56859485/does-c-standard-library-provide-more-compact-and-generalized-version-of-the-er