代码之家  ›  专栏  ›  技术社区  ›  Awanish Golwara

对映射容器使用remove_if

  •  4
  • Awanish Golwara  · 技术社区  · 9 年前

    我试图将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.0\VC\INCLUDE\utility(260) : error C2166: l-value specifies const object
            C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\INCLUDE\utility(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
            ]
    
    3 回复  |  直到 9 年前
        1
  •  5
  •   Community Marino Di Clemente    7 年前

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

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

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

        2
  •  2
  •   Jonathan Potter    9 年前

    这个小 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); 
    
        3
  •  1
  •   Toby Speight    7 年前

    您不能使用 remove_if 在…上 map ,因为它的值类型实际上是 std::pair<const Key, Value> 但你看 requirements of remove_if 可以看到,取消引用的迭代器类型应该是 MoveAssignable .

    只需写循环,或者使用boost。

    推荐文章