将remove_if用于地图容器

using remove_if for a map container

本文关键字:地图 用于 if remove      更新时间:2023-10-16

我试图将remove_if模板用于地图容器,但模板参数的编译器错误。我不明白为什么。

int main()
{
  map<const int, int> intmap;
  intmap[1] = 1;
  intmap[2] = 2;
  intmap[3] = 3;
  intmap[4] = 4;
  auto isOdd = [&](pair<const int, int> it)->bool 
     { return static_cast<bool>(it.second % 2); };
  isOdd(*(intmap.begin()));
 remove_if(intmap.begin(), intmap.end(), isOdd); 
}

此remove_if引发编译器错误。有什么建议可以解决吗?

错误消息是

C:Program Files (x86)Microsoft Visual Studio 10.0VCINCLUDEutility(260) : error C2166: l-value specifies const object
        C:Program Files (x86)Microsoft Visual Studio 10.0VCINCLUDEutility(259) : while compiling class template member function 
        'std::pair<_Ty1,_Ty2> &std::pair<_Ty1,_Ty2>::operator =(std::pair<_Ty1,_Ty2> &&)'
        with
        [
            _Ty1=const int,
            _Ty2=int
        ]
        maperaseif.cpp(29) : see reference to class template instantiation 'std::pair<_Ty1,_Ty2>' being compiled
        with
        [
            _Ty1=const int,
            _Ty2=int
        ]

>remove_if通过扫描元素来工作,一旦要删除一个元素,它就会记住将留下的"间隙"(保持一个迭代器指向它),同时推进另一个迭代器以找到下一个要保留的元素......然后,它开始将元素从后一个位置复制或移动到前一个位置,直到到达end()

这不适用于map,因为你不能完全覆盖pair<key,value>元素:不允许修改键值,或者实现所需的排序顺序不变性可能失效。

所以,你需要放弃remove_if. 您可以使用普通循环,小心保存迭代器到下一个元素,而不是尝试从刚刚擦除的迭代器前进。 关于如何在迭代时从地图中删除元素的许多其他问题,例如这里......

这个erase_if模板化的小函数应该可以做你想做的事。(我没有写它,只是从某个地方捡起它 - 所以要归功于谁!

  template< typename ContainerT, typename PredicateT >
  void erase_if( ContainerT& items, const PredicateT& predicate ) {
    for( auto it = items.begin(); it != items.end(); ) {
      if( predicate(*it) ) it = items.erase(it);
      else ++it;
    }
  };

在您的示例中,您将像这样使用它:

erase_if(intmap, isOdd); 
你不能

map上使用remove_if,因为它的值类型实际上是std::pair<const Key, Value>的,但是你看看remove_if的要求,你可以看到,取消引用的迭代器类型应该是MoveAssignable的。

只需编写循环,或使用 boost 例如。