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

时间:2014-06-17 12:01:13

标签: c++ stl set std

此代码包含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一起使用?

3 个答案:

答案 0 :(得分:13)

您不能将std::remove_if()用于包含const部分的序列。 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())。

答案 1 :(得分:4)

std::remove_if重新排序元素,因此无法与std::set一起使用。但您可以使用std::set::erase

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

答案 2 :(得分:1)

从 C++20 开始,您可以将 std::erase_if 用于具有 erase() 方法的容器,正如 Kühl 解释的那样。 请注意,这也包括 std::vector,因为它具有擦除方法。不再链接 a.erase(std::remove_if(... :)