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

IntelC++から次のエラーが発生します。

エラー:囲んでいるラムダは暗黙的なキャプチャを許可しないため、この囲んでいる関数のローカル変数はこのラムダ本体で参照できません

エラーが参照している囲み関数のローカル変数は、「const Entity *&entity」です。

ラムダ変数のキャプチャメソッドを[&]から[&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;
}

イテレータでさえ、どのラムダアプローチよりもはるかにソートされていることに注意してください。

于 2012-12-03T04:59:12.437 に答える
3

私が見る限り、内側と外側のラムダでも「名前」をキャプチャする必要があります。
一方、エンティティは関数の引数であるため、キャプチャしてはなりません。

また、を使用することはお勧めしませんstd::list<Entity*>>。一部のコンパイラは前者をoperator<およびoperator>>と誤解するため、
むしろ使用してください。std::list<Entity*> >

コンパイルするようにコードを修正しました:(string & name参照によってキャプチャされます)

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

このコードを再確認しますが、問題はないはずです。(さらにいくつかの&を置き忘れた場合を除いて、ペアはconst refである必要があり、entityは単なるconstポインターである必要があります。)

提案:コードをもう少し読みやすくするために、ラムダヘッダーを次の行に分割し、関数内で使用することもできますusing namespace std

更新:コードにはまだバグがあります。returnラムダからのみ返されますが、見つかったエンティティは返されません。

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の代わりにbeginandを使用し、end後方に検索するときに最初のものを見つけます。

于 2012-12-03T03:20:34.093 に答える