C++ std::set::erase with std::remove_if

C++ std::set::erase with std::remove_if

本文关键字:std remove if erase set C++ with      更新时间:2023-10-16

此代码具有Visual Studio error C3892。如果我把std::set改为std::vector -它工作

std::set<int> a;
a.erase(std::remove_if(a.begin(), a.end(), [](int item)
{
    return item == 10;
}), a.end());

怎么了?为什么我不能用std::remove_ifstd::set ?

不能对含有const部分的序列使用std::remove_if()std::set<T>元素序列由T const对象组成。实际上,就在昨天,我们在标准c++委员会上讨论了这个问题,并且有一些支持来创建专门处理容器中的erase()对象的算法。它看起来像这样(参见N4009):

template <class T, class Comp, class Alloc, class Predicate>
void discard_if(std::set<T, Comp, Alloc>& c, Predicate pred) {
    for (auto it{c.begin()}, end{c.end()}; it != end; ) {
        if (pred(*it)) {
            it = c.erase(it);
        }
        else {
            ++it;
        }
    }
}

(它实际上可能会委托一个算法调度上面的逻辑,因为相同的逻辑对于其他基于节点的容器是相同的)。

对于您的特定用途,可以使用

a.erase(10);

,但这只适用于当你想要删除一个键时,而上面的算法适用于任意谓词。另一方面,a.erase(10)可以利用std::set<int>的结构,将是O(log N),而算法是O(N)(使用N == s.size())。

从c++ 20开始,您可以对具有erase()方法的容器使用std::erase_if,正如k hl解释的那样。

// C++20 example:
std::erase_if(setUserSelection, [](auto& pObject) {
                                     return !pObject->isSelectable();
                                });

注意这也包括std::vector,因为它有一个擦除方法。没有更多的链接a.erase(std::remove_if(...:)

std::remove_if重新排序元素,所以它不能与std::set一起使用。但是你可以使用std::set::erase:

std::set<int> a;
a.erase(10);