如何使用STL算法和仿函数按值擦除std :: map单元格?

时间:2013-08-22 08:56:44

标签: c++ map stl

我用C ++编写了一个小型测试实体管理器。我有一个名为'removeEntityByName'的方法,使用简单的擦除。直到这里没有问题。现在我有另一个名为'removeEntityByPtr'的方法,它必须按值删除。这是有效的代码:

void EntityManager::removeEntityByPtr(Entity *pEntity)
{
    std::map<std::string, Entity*>::iterator It = this->m_EntityList.begin();

    for (; It != this->m_EntityList.end();) {
        if ((*It).second == pEntity) {
            this->m_EntityList.erase(It++);
        } else {
            ++It;
        }
    }
}

但它不是很漂亮。所以,我想知道我是否能找到一种更优雅的方式使用STL算法和仿函数来正确地完成工作(我知道std :: vector没有问题,但是使用std :: map我不确定它是否有效)。所以这是我尝试使用的不同仿函数:

template <typename T>
struct DeleteFunctor
{
    DeleteFunctor(T *pointer)
        :   m_Pointer(pointer)
    {

    }

    bool operator()(std::string, Entity *pEntity)
    {
        if (pEntity == this->m_Pointer) {
            delete(this->m_Pointer);
            return (true);
        }
        return (false);
    }

    T *m_Pointer;
};

template <typename T>
struct DeleteFunctor
{
    DeleteFunctor(T *pointer)
        :   m_Pointer(pointer)
    {

    }

    bool operator()(std::pair<std::string, Entity*> const &cell)
    {
        if (cell.second == this->m_Pointer) {
            delete(this->m_Pointer);
            return (true);
        }
        return (false);
    }

    T *m_Pointer;
};

和STL算法:

this->m_EntityList.erase(std::remove(this->m_EntityList.begin(), this->m_EntityList.end(), DeleteFunctor<Entity>(pEntity)), this->m_EntityList.end());

我想确切地说Visual Studio的语法是正确的。但编译失败了。

以下是编译错误:

error C2678: binary '==' : no operator found which takes a left-hand operand of type 'std::pair<_Ty1,_Ty2>'
 with
[
   _Ty1=const std::string,
   _Ty2=Entity *
]
c:\program files (x86)\microsoft visual studio 11.0\vc\include\exception(507): peut être 'bool std::operator ==(const std::exception_ptr &,const std::exception_ptr &)'
c:\program files (x86)\microsoft visual studio 11.0\vc\include\exception(512): ou       'bool std::operator ==(std::nullptr_t,const std::exception_ptr &)'
c:\program files (x86)\microsoft visual studio 11.0\vc\include\exception(517): ou       'bool std::operator ==(const std::exception_ptr &,std::nullptr_t)'
c:\program files (x86)\microsoft visual studio 11.0\vc\include\system_error(426): ou       'bool std::operator ==(const std::error_code &,const std::error_condition &) throw()'
c:\program files (x86)\microsoft visual studio 11.0\vc\include\system_error(434): ou       'bool std::operator ==(const std::error_condition &,const std::error_code &) throw()'
when attempting matching of the argument list '(std::pair<_Ty1,_Ty2>, const DeleteFunctor)'
with
[
  _Ty1=const std::string,
  _Ty2=Entity *
]
c:\program files (x86)\microsoft visual studio 11.0\vc\include\algorithm(1788) : see the reference of the model function '_FwdIt std::_Remove<std::_Tree_unchecked_iterator<_Mytree>,_Ty>(_FwdIt,_FwdIt,const _Ty &)' en cours de compilation
with
[     _FwdIt=std::_Tree_unchecked_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const std::string,Entity *>>>>,
 _Mytree=std::_Tree_val<std::_Tree_simple_types<std::pair<const std::string,Entity *>>>,
 _Ty=DeleteFunctor
]
c:\users\volodia\desktop\testmanager\testmanager\entitymanager.cpp(76) : voir la référence à l'instanciation de la fonction modèle '_FwdIt std::remove<std::_Tree_iterator<_Mytree>,DeleteFunctor>(_FwdIt,_FwdIt,const _Ty &)' en cours de compilation
with
[
 _FwdIt=std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const std::string,Entity *>>>>,
  _Mytree=std::_Tree_val<std::_Tree_simple_types<std::pair<const std::string,Entity *>>>,
  _Ty=DeleteFunctor
]

我尝试了几种代码组合而没有任何成功。有人能帮帮我吗?非常感谢您的帮助。

1 个答案:

答案 0 :(得分:3)

许多算法(包括std::remove)通过在容器中移动元素来工作。例如,std::remove将不需要的元素交换到后面,而想要放在前面。

std::mapstd::set之类的关联容器中不允许这样做,因为存储的元素中的顺序是固定的,因此您无法在容器上使用这些算法。

话虽如此,您所做的第一种方法是正确的,尽管您可以将算法与逻辑分开:

template <class Container, class Pred>
void erase_if(Container& cont, Pred pred) {
  for (auto first = begin(cont), last = end(cont); first != last;)
  {
    if (pred(*first))
      first = cont.erase(first);
    else
      ++first;
  }
}

然后在你的代码中(C ++ 14风格):

void EntityManager::removeEntityByPtr(Entity *pEntity)
{
  erase_if(this->m_EntityList, [=](auto const& keyValue) { 
    return keyValue.second == pEntity;
  }
}

在C ++ 11 中,您必须指定lambda函数参数的类型,即std::pair<std::string const, Entity*>
在C ++ 03 中,您必须滚动一个额外的仿函数,在erase_if for循环中指定迭代器类型,就像在示例中一样,并调用begin和{ {1}}容器的成员函数,而不是C ++ 11中引入的自由函数