【问题标题】:C++ std::set::erase with std::remove_ifC++ std::set::erase 与 std::remove_if
【发布时间】:2014-08-07 10:23:49
【问题描述】:

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

【问题讨论】:

标签: c++ stl set std


【解决方案1】:

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

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

【讨论】:

  • 好的,谢谢。但。这是个问题吗?让它重新排序。因为复杂?
  • @herolover std::set 是有序的,并且它的对数查找需要排序(它是一个二叉搜索树)。所以它与复杂性有关。
  • @herolover std::set 元素顺序由比较器函数预先确定,您无法更改顺序,容器不起作用
【解决方案2】:

您不能将std::remove_if() 与具有const 部分的序列一起使用。 std::set&lt;T&gt; 元素的序列由 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;
        }
    }
}

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

具体用途,可以使用

a.erase(10);

但这只有在你想删除一个键时才有效,而上面的算法适用于任意谓词。另一方面,a.erase(10) 可以利用std::set&lt;int&gt; 的结构,并且算法为 O(log N),而算法为 O(N)(与N == s.size())。

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多