2

这是我目前正在使用的一些代码:

Entity *Engine::findEntity(const std::string &name)
{
    std::for_each(p_entities.begin(), p_entities.end(),[](std::pair<const int, const std::list<Entity*>> pair) {

        std::for_each((pair.second).begin(),(pair.second).end(),[&](const Entity* &entity) {

            if ( entity->getAlive() == true && entity->getName() == name )
                return entity;
        });
    });
    return nullptr;
}

我从 intel c++ 收到以下错误:

错误:无法在此 lambda 主体中引用此封闭函数局部变量,因为封闭 lambda 不允许隐式捕获

错误所指的封闭函数局部变量是“const Entity* &entity”。

如果我将 lambda 变量捕获方法从 [&] 更改为 [&entity],我会收到以下错误:

错误:标识符“实体”未定义

我想了解为什么会发生这种情况以及我可以做些什么来解决这个问题。

4

3 回答 3

4

如果我们在 C++11 中有更好的 for-each,为什么还要为 std::for_each、find_if 或迭代器烦恼?

编码更短:

const Entity *Engine::findEntity(const std::string &name)
{
  for(auto& eit : p_entities)
    for(auto pe : eit.second)
      if ( pe->getAlive() == true && pe->getName() == name )
        return pe;

  return nullptr;
}

只需将其与基于迭代器的解决方案进行比较:

//...
#include <iterator> // do not forget this.

typedef std::map<int, const std::list<Entity*> > entity_map_t;

const Entity *Engine::findEntity(const std::string &name)
{
  using namespace std;
  const Entity* found_entity = nullptr;

  entity_map_t::iterator eit;
  for(eit=p_entities.begin(); (!found_entity) && eit!=p_entities.end(); ++eit)
  {
    list<Entity*>::const_iterator it_pEntity; // I called this originally lit. Maybe this is more expressive
    for(it_pEntity=eit->second.begin(); (!found_entity) && it_pEntity!=eit->second.end(); ++it_pEntity)
    {
      if ( (*it_pEntity)->getAlive() == true && (*it_pEntity)->getName() == name )
           found_entity = *it_pEntity;
    }
  }
  return found_entity;
}

请注意,即使是迭代器也比任何 lambda 方法都要排序。

于 2012-12-03T04:59:12.437 回答
3

据我所知,您还需要在内部和外部 lambda 中捕获“名称”。
另一方面,实体不能被捕获,因为它是一个函数参数。

另外,我不鼓励您使用std::list<Entity*>>.
使用相当std::list<Entity*> >,因为一些编译器将前者误解为 operator< 和 operator>>。

更正了代码以使其编译:(string & name由 ref 捕获。)

Entity *Engine::findEntity(const std::string &name)
{
    using namespace std;

    for_each(p_entities.begin(), p_entities.end(),
      [&name](pair<const int, const list<Entity*>>& pair) 
      {
        for_each((pair.second).begin(),(pair.second).end(),
          [&name](const Entity* entity) 
          {
             if ( entity->getAlive() == true && entity->getName() == name )
               return entity;
          });
      });
    return nullptr;
}

我会仔细检查这段代码,但现在应该没问题。(除了你放错了一些 &'s:pair 应该是 const ref,entity 应该只是一个普通的 const 指针。)

建议:为了使您的代码更具可读性,您可以将 lambda 标头拆分到下一行,也可以使用 in-function using namespace std

更新:您的代码中仍然存在错误。return仅从 lambda 返回,但找到的实体永远不会返回。

UPDATE2:进一步更正,以便函数正确运行:

// returns the last found entity.
const Entity *Engine::findEntity(const std::string &name)
{
    using namespace std;
    const Entity * found_entity=nullptr;

    for_each(p_entities.begin(), p_entities.end(),
      [&name, &found_entity](pair<const int, const list<Entity*> >& pair) 
      {
        for_each((pair.second).begin(),(pair.second).end(),
          [&name, &found_entity](const Entity* entity) 
          {
             if( entity->getAlive() == true && entity->getName() == name )
               found_entity = entity; // here you need to modify the variable captured from the outside.
          });
      });
    return found_entity;
}

但我不会for_each在这种情况下使用,因为它没有,break所以即使在找到实体之后它也必须完成循环。我宁愿在这里使用迭代器。


这部分仅适用于 OP。这就是我填补空白的方式(整个代码):

#include <iostream>
#include <list>
#include <string>
#include <map>
#include <algorithm> 

class Entity{

public:
  bool getAlive() const {return true;}
  std::string getName() const {return "Barna";}
};

class Engine{

public:
  const Entity *findEntity(const std::string& name);
private:
  std::map<int, const std::list<Entity*> > p_entities;
};

const Entity *Engine::findEntity(const std::string &name)
{
  using namespace std;
  const Entity* found_entity = nullptr;
  for_each(p_entities.begin(), p_entities.end(),
      [&name, &found_entity](pair<const int, const list<Entity*> >& pair) 
      { 
        for_each((pair.second).begin(),(pair.second).end(),
          [&name, &found_entity](const Entity* entity) 
          {
            if ( entity->getAlive() == true && entity->getName() == name )
               found_entity = entity;
          });
      });
  return found_entity;
}

int main()
{
  Engine e;
  e.findEntity("he");
}
于 2012-12-03T02:25:06.593 回答
1

这是 Barnabas 解决方案的一个稍微高效的版本:

// returns the first found entity.
const Entity *Engine::findEntity(const std::string &name)
{
  using namespace std;
  const Entity * found_entity=nullptr;

  find_if(p_entities.begin(), p_entities.end(),
    [&name,&found_entity](pair<const int, const list<Entity*> >& pair) 
    {
      auto it = find_if((pair.second).begin(),(pair.second).end(),
        [&name](const Entity* entity) 
        {
          if( entity->getAlive() == true && entity->getName() == name )
            return true;
          else
            return false;
        }
      );
      if (it != (pair.second).end()) {
        found_entity = *it;
        return true;
      } else {
        return false;
      }
    }
  );
  return found_entity;
}

请注意,这将返回第一个找到的实体。如果您想要最后一个,而不是向前搜索,请使用rbeginandrend代替beginandend并在向后搜索时找到第一个。

于 2012-12-03T03:20:34.093 回答