如何使用STL算法和仿函数按值擦除std :: map单元格?(How to erase a std::map cell by value using STL algorithms and funct

编程入门 行业动态 更新时间:2024-10-25 20:22:25
如何使用STL算法和仿函数按值擦除std :: map单元格?(How to erase a std::map cell by value using STL algorithms and functors?)

我用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 ]

我尝试了几种代码组合但没有成功。 有人可以帮我吗? 非常感谢您的帮助。

I coded a small test entity manager in C++. I have a method called 'removeEntityByName' using a simple erase. Until here there is none problem. Now I have another method called 'removeEntityByPtr' which must delete by value. Here's the code which works :

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; } } }

But it's not very beautiful. So, I wondered if I could find a more elegant way using STL algorithms and functors to do the job correctly (I know there is no problem with std::vector but with std::map I'm not sure it works). So here's the different functors I tried to use:

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; };

And the STL algorithms :

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

I want to precise that the syntax is correct with Visual Studio. But the compilation failed.

Here's the compilation errors :

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 ]

I tried several code combinations without any success. Does anyone can help me please ? Thanks a lot in advance foir your help.

最满意答案

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

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

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

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函数,在您的示例中指定erase_if for循环内的迭代器类型,并调用容器的begin和end成员函数,而不是C ++中引入的自由函数11

Many algorithms, including std::remove work by moving elements around in a container. For example, std::remove swaps unwanted elements to the back, and the wanted to the front.

This is not allowed in associative containers like std::map and std::set, because the order in wich elements are stored is fixed, so you can't use those algorithms on the containers.

Having said that, the first approach you made is correct, although you could separate the algorithm from the logic:

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; } }

And then in your code (C++14 style):

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

In C++11 you'll have to specify the type of the lambda function parameter, which is std::pair<std::string const, Entity*>. In C++03 you have to roll an extra functor, specify the iterator type inside the erase_if for loop like you did in your example, and call the begin and end member functions of the container instead of the free functions introduced in C++11

更多推荐

本文发布于:2023-08-04 07:35:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1412740.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:如何使用   算法   单元格   函数   擦除

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!