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

her*_*ver 6 c++ stl std set

此代码具有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());
Run Code Online (Sandbox Code Playgroud)

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

Die*_*ühl 17

您不能使用std::remove_if()包含const部分的序列.std::set<T>元素序列由T const对象组成.我们昨天在标准的C++委员会中实际上讨论了这个问题,并且有一些支持来创建专门erase()处理来自容器的ing对象的算法.它看起来像这样(另见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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

对于您的具体用途,您可以使用

a.erase(10);
Run Code Online (Sandbox Code Playgroud)

但这仅适用于上述算法与任意谓词一起使用时删除键的情况.另一方面,a.erase(10)可以利用std::set<int>结构,并且当算法是O(N)(with N == s.size())时将是O(log N ).


小智 11

从 C++20 开始,您可以将std::erase_if用于具有方法的容器erase(),正如K\xc3\xbchl所解释的那样。

\n
// C++20 example:\nstd::erase_if(setUserSelection, [](auto& pObject) {\n                                     return !pObject->isSelectable();\n                                });\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,这也包括std::vector,因为它有一个擦除方法。不再需要链接a.erase(std::remove_if(...:)

\n


jua*_*nza 5

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

std::set<int> a;
a.erase(10);
Run Code Online (Sandbox Code Playgroud)