C++ 标准库是否提供更紧凑和通用的擦除 - 删除惯用语版本?
Does C++ standard library provide more compact and generalized version of the erase–remove idiom?
我们可以通过流行的erase–remove idiom 从容器中删除一个元素/条目。
然而,我们中的许多人在应用这个成语时会遇到一些问题:
一个人很容易陷入打字错误的陷阱 like
c.erase(std::remove_if(c.begin(), c.end(), pred));
// , c.end() //---> missing here
或
c.erase((std::remove_if(c.begin(), c.end(), pred), c.end()))
// ^^ ^^
// extra () makes it pass only c.end() to the c.erase
- 它甚至遵循错误的语义
std::list
不选择自己的成员
std::list::remove_if()
对于成语。
- 第三,使用
std::remove_if
对关联不起作用
容器.
在 c++17, or will there be such a utility in c++20 的范围内,我们是否有比 std::erase-std::remove_if
或类似 std::erase_if
更普遍且更不易打错字的东西?
不在c++17, but c++20以后的范围内!
是。 n4009 paper and finally adopted in C++20 standard as std::erase_if
中提到了一致性容器擦除的提议,即每个容器的non-member功能。
这确保了 std::basic_string
和 all standard containers 的统一容器擦除语义,除了 std::array
(因为它具有 fixed-size)。
这意味着样板代码
container.erase(
std::remove_if(
container.begin(), container.end(),
[](const auto& element) ->bool { return /* condition */; }),
vec.end());
将简单地分解为
的 广义形式
std::erase_if(container, [](const auto& element) ->bool { return /* condition */; });
其次,这种统一的语法为每个容器选择了正确的语义。这意味着
对于像 std::vector
, std::deque
这样的序列容器,对于
std::std::basic_string
,将等同于
container.erase(
std::remove_if(container.begin(), container.end(), unaryPredicate)
, container.end()
);
对于序列容器std::forward_list
and std::list
,它将
相当于
container.remove_if(unaryPredicate);
对于有序关联容器(即 std::set
, std::map
,
std::multiset
and std::multimap
) 和无序关联
容器(即 std::unordered_set
, std::unordered_map
,
std::unordered_multiset
and 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;
}
}
除此之外,标准还为形式为
的序列容器添加了std::erase
std::erase(container, value_to_be_removed);
我们可以通过流行的erase–remove idiom 从容器中删除一个元素/条目。 然而,我们中的许多人在应用这个成语时会遇到一些问题:
一个人很容易陷入打字错误的陷阱 like
c.erase(std::remove_if(c.begin(), c.end(), pred)); // , c.end() //---> missing here
或
c.erase((std::remove_if(c.begin(), c.end(), pred), c.end())) // ^^ ^^ // extra () makes it pass only c.end() to the c.erase
- 它甚至遵循错误的语义
std::list
不选择自己的成员std::list::remove_if()
对于成语。 - 第三,使用
std::remove_if
对关联不起作用 容器.
在 c++17, or will there be such a utility in c++20 的范围内,我们是否有比 std::erase-std::remove_if
或类似 std::erase_if
更普遍且更不易打错字的东西?
不在c++17, but c++20以后的范围内!
是。 n4009 paper and finally adopted in C++20 standard as std::erase_if
中提到了一致性容器擦除的提议,即每个容器的non-member功能。
这确保了 std::basic_string
和 all standard containers 的统一容器擦除语义,除了 std::array
(因为它具有 fixed-size)。
这意味着样板代码
container.erase(
std::remove_if(
container.begin(), container.end(),
[](const auto& element) ->bool { return /* condition */; }),
vec.end());
将简单地分解为
的 广义形式std::erase_if(container, [](const auto& element) ->bool { return /* condition */; });
其次,这种统一的语法为每个容器选择了正确的语义。这意味着
对于像
std::vector
,std::deque
这样的序列容器,对于std::std::basic_string
,将等同于container.erase( std::remove_if(container.begin(), container.end(), unaryPredicate) , container.end() );
对于序列容器
std::forward_list
andstd::list
,它将 相当于container.remove_if(unaryPredicate);
对于有序关联容器(即
std::set
,std::map
,std::multiset
andstd::multimap
) 和无序关联 容器(即std::unordered_set
,std::unordered_map
,std::unordered_multiset
andstd::unordered_multimap
),std::erase_if
等同于for (auto i = container.begin(), last = container.end(); i != last; ) { if (unaryPredicate(*i)) { i = container.erase(i); } else { ++i; } }
除此之外,标准还为形式为
的序列容器添加了std::erase
std::erase(container, value_to_be_removed);