JeJ*_*eJo 18 c++ c++-standard-library erase-remove-idiom c++17 c++20
我们可以通过流行的“ 删除-删除”惯用语从容器中删除一个元素/条目。但是,在应用此惯用语时,我们许多人会遇到一些问题:
人们可以很容易陷入的陷阱错别字像
c.erase(std::remove_if(c.begin(), c.end(), pred));
// , c.end() //---> missing here
Run Code Online (Sandbox Code Playgroud)
要么
c.erase((std::remove_if(c.begin(), c.end(), pred), c.end()))
// ^^ ^^
// extra () makes it pass only c.end() to the c.erase
Run Code Online (Sandbox Code Playgroud)std::list不std::list::remove_if()
为习惯用语选择自己的成员
。std::remove_if 不适用于关联容器。在c ++ 17的范围内,我们是否有比python范围更广,更不易打错的std::erase-std::remove_if东西,或者c ++ 20中是否会有这样的工具?std::erase_if
JeJ*_*eJo 27
是的。在n4009论文中提到了一致的容器擦除的建议,并最终在C ++ 20标准中std::erase_if采用,因为它是每个容器的非成员函数。
这确保了均匀的容器擦除语义std::basic_string和所有标准容器,除了std::array(因为它具有固定大小)。
这意味着样板代码
container.erase(
std::remove_if(
container.begin(), container.end(),
[](const auto& element) ->bool { return /* condition */; }),
vec.end());
Run Code Online (Sandbox Code Playgroud)
将简单地熔化至一广义形式的
std::erase_if(container, [](const auto& element) ->bool { return /* condition */; });
Run Code Online (Sandbox Code Playgroud)
其次,这种统一的语法为每个容器选择适当的语义。这意味着
对于序列容器,如std::vector,std::deque和
std::std::basic_string,这将等同于
container.erase(
std::remove_if(container.begin(), container.end(), unaryPredicate)
, container.end()
);
Run Code Online (Sandbox Code Playgroud)对于序列容器std::forward_list和std::list,它等效于
container.remove_if(unaryPredicate);
Run Code Online (Sandbox Code Playgroud)对于有序关联容器(即std::set,std::map,
std::multiset和std::multimap)和无序关联式容器(即std::unordered_set,std::unordered_map,
std::unordered_multiset和std::unordered_multimap)时,
std::erase_if相当于
for (auto i = container.begin(), last = container.end(); i != last; )
{
if (unaryPredicate(*i))
{
i = container.erase(i);
}
else
{
++i;
}
}
Run Code Online (Sandbox Code Playgroud)除此之外,该标准还添加std::erase了以下形式的序列容器
std::erase(container, value_to_be_removed);
Run Code Online (Sandbox Code Playgroud)