универсальный метод поиска? - PullRequest
0 голосов
/ 16 июля 2009

Мне нужен универсальный метод для извлечения данных из вектора.

У меня есть следующий класс и вектор:

class myClass
{
    public:

    myClass(int myX, float myZ, std::string myFoo)
        : x ( myX )
        , z ( myZ )
        , foo ( myFoo )
    {

    }
    myClass()
    {

    }

    int x;
    float z;
    std::string foo;

} ;
std::vector < myClass > myVector;

(полный код можно посмотреть здесь: http://codepad.org/iDD1Wme5)

В этом примере я хотел бы иметь возможность извлекать объекты в векторе на основе членов "z" или "foo" без необходимости писать еще 2 функции, подобные "FindDataById".

Это возможно?

Ответы [ 5 ]

4 голосов
/ 16 июля 2009

Вы можете использовать шаблон и указатель на член.

typedef vector<myClass> myVector;

template<typename T>
bool FindDataById(const T &id, T myClass::* idMember, myClass &theClass,
                                                       const myVector &theVector)
{
   for(myVector::const_iterator itr = theVector.begin(); itr != myVector.end();
                                                                          ++itr){
       if((*itr).*idMember == id){
          theClass = *itr;
          return true;
   }

   return false;
}

Затем позвоните, используя, например,

FindDataById(string("name"), &myClass::foo, theClass, theVector)
FindDataById(5, &myClass::x, theClass, theVector)
FindDataById(5.25f, &myClass::z, theClass, theVector)

Или идите с идеей find_if:

template<typename T>
struct Finder {
   T val_;
   T myClass::* idMember_;

   Finder(T val, T myClass::* idMember) : val_(val), idMember_(idMember) {}
   bool operator()(const myClass &obj) { return obj.*idMember_ == val_; }
};

И использовать:

find_if(theVector.begin(), theVector.end(), Finder<string>("name", &myClass::foo))
find_if(theVector.begin(), theVector.end(), Finder<int>(5, &myClass::x))
find_if(theVector.begin(), theVector.end(), Finder<float>(3.25f, &myClass::z))

См. Ответ MSalters о способе автоматического вывода аргумента шаблона.

1 голос
/ 16 июля 2009

std::find_if уже было предложено, но без примера кода, поэтому вот более подробная версия:

Определите два функтора для идентификации интересующего вас объекта:

struct z_equals {
  z_equals(float z) : z(z) {}

  bool operator()(const myClass& obj)
    return z == obj.z;
  }

  float z;
};


struct foo_equals {
  foo_equals(const std::string& foo) : foo(foo) {}

  bool operator()(const myClass& obj)
    return foo == obj.foo;
  }

  const std::string& foo;
};

А теперь, чтобы искать элементы, где z == 42.0f или foo == "hello world":

std::find_if(myVector.begin(), myVector.end(), z_equals(42.0f));
std::find_if(myVector.begin(), myVector.end(), foo_equals("hello world"));
0 голосов
/ 16 июля 2009

Без лямбды вам нужно написать несколько предикатов или, по крайней мере, создать их экземпляр:

template
struct member_select : public std::unary_function
{
  T t;
  T U::* m_u;
  member_select(T const& t, T U::* m_u) : t(t), m_u(m_u) {}
  bool operator()(U const& u) const { return u.*m_u == t; }
};

template
member_select make_member_select(T const& t, T U::* m_u)
{
  return member_select(t, m_u);
}

Использование: std::find_if(..., make_member_select("x", &myClass::foo));

0 голосов
/ 16 июля 2009

Возможно, стоит взглянуть на std :: find, определенный в алгоритме, и boost :: lambda

0 голосов
/ 16 июля 2009

Вы можете использовать функторы и передать их в свой метод поиска. Я имею в виду, определите класс, который будет перегружать bool operator( vectorElement element), и внутри этого оператора вы выберете метод, как вы хотите искать значения.

template <typename T>
class ILookUp
{
    bool operator( vector<T> elem)
    {
      if (elem == something)
          return true;
      false;
    }
};

class VectorStorage
{
     std::vector<Elements> lookup( ILookUp<Elements> lookup)
     {

         .....         

         if ( lookup(elem))
         {
              //add element to vector or whatever.
         }

          .....

         return result;
     }

          .....

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