Использование find_if на карте для поиска по значению - PullRequest
4 голосов
/ 23 декабря 2010

У меня есть класс с картой. Мне нужно найти итератор в карте путем поиска определенного значения, а не ключа. Использование предиката функции-члена IsValueFound, я пытаюсь это.

class A
{
public:
  void findVal();
private:
 int state;
 map<int, int> exmap;
 bool IsValueFound(pair<int key, int val> itr)
 {
   return state == itr.second;
 }
};

void A::findVal
{
  itr = find_if(exmap.begin, exmap.end, mem_fun1_ref(&A::IsValueFound));
}

Я получаю ошибки компиляции. Я не уверен, каков синтаксис для этих функциональных адаптеров. Пожалуйста, помогите.

РЕДАКТИРОВАТЬ: Извините. Пожалуйста, пренебрегайте ошибками компиляции, возникающими, кроме как из finf_if stmt. Мне нужно сначала исправить find_if stmt. Также код не имеет повышения: (

Ответы [ 7 ]

4 голосов
/ 23 декабря 2010

Немного проще преобразовать объект А в функтор:
Но были и другие проблемы с вашим кодом (см. Ниже):

#include <map>
#include <memory>
#include <functional>
#include <algorithm>

using namespace std;

class A {
    public:
      void findVal();
    private:
      int state;
      map<int, int> exmap;

      // Changed the function IsValueFound() to operator()
      // This makes the whole object behave like a function.
      // Its a lot easier then getting member functions and binding
      // the this reference.
      bool operator()(map<int,int>::value_type const& itr) const
                    //         ^^^^^^^^^^^^^^^^^
                    //  std::pair<int,int> is not the type held in the map
                    //  so you are not going to bind against it using a pair.
      {
          return state == itr.second;
      }
};

void A::findVal()
{
    // You did not specify a type
    // for the iterator in your code.
    std::map<int,int>::iterator itr1 = find_if(exmap.begin(), exmap.end(), *this);
                                                   //   ^^^^^^       ^^^^^^
                                                   // begin() and end() are methods.

    // Just pass the `this` object as the the third parameter it will act as a function now.
}
3 голосов
/ 23 декабря 2010

Изменить : очевидно, в моем ответе ошибка , mem_fun1_ref(&A::IsValueFound) не работает как предикат для std::find_if. Я работаю над исправлением этого.

вы забыли круглые скобки с exmap.begin и exmap.end. Я думаю, что если бы вы прочитали отчет об ошибке компиляции, он бы кое-что об этом сказал.

Я бы написал так:

typedef map<int, int>::const_iterator MyIterator
void A::findVal()
{
    const MyIterator itrBegin = exmap.begin();
    const MyIterator itrEnd = exmap.end();
    MyIterator itrFound = find_if( itrBegin ,
                                   itrEnd ,
                                   mem_fun1_ref(&A::IsValueFound));    
}

но я не пробовал mem_fun1_ref(&A::IsValueFound) скомпилировать. и я не привык использовать mem_fun1_ref, я всегда переопределяю свой собственный функтор с помощью operator().

2 голосов
/ 23 декабря 2010

Если вы не хотите использовать Boost Bimap, вы можете создать так называемый функтор, объект, который перегружает оператор вызова функции (). В этом куске кода:

class A {
public:
bool findVal(int s);

private:
map<int, int> exmap;

struct IsValueFound {
    int state;
    IsValueFound(int _state) : state(_state) {};
    bool operator()(const pair<int, int>& itr) {
        return state == itr.second;
    }
};  

};

bool A::findVal(int x) {
    return (find_if(exmap.begin(), exmap.end(), A::IsValueFound(x)) != exmap.end());
}
1 голос
/ 23 декабря 2010

mem_fun_ref принимает функцию с одним аргументом

bool IsValueFound(pair<int, int> itr)

и превращает его в функтор с двумя аргументами:

bool functor(A& this, pair<int, int> itr).

где ссылка, используемая в качестве первого параметра, используется для генерации указателя this для вызова функции-члена IsValueFound.

Вы, вероятно, не хотите ничего связанного здесь * 1017 - связыватели будут работать просто отлично:

std::find_if(exmap.begin, exmap.end, std::bind2nd(std::equal_to<int>(), state));

Просто понял, что это не сработает для итератора карты ... Возможно, я бы просто написал явный цикл на этом этапе.

Есть несколько синтаксических ошибок, которые у вас здесь есть, но @martona уже их коснулась, поэтому я не буду бить мертвую лошадь :) 10 *

1 голос
/ 23 декабря 2010

Что касается ошибок компиляции, вы объявляете свой итератор неверным в списке аргументов IsValueFound, например.Это должно быть:

map<int, int>::iterator itr

Тогда в A :: findVal itr вообще не объявляется.

Сказав это, сканирование карты для значений не является хорошей идеей, если вам нужноделай это часто.Вы должны рассмотреть какое-то другое внутреннее представление ваших данных.

0 голосов
/ 23 декабря 2010

Просто используйте Boost Bimap .

0 голосов
/ 23 декабря 2010

вы на самом деле используете свою карту как bi-directional map, так что вам может пригодиться Boost Multi-index Containers boost. У них есть конкретный пример реализации двунаправленной карты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...