2009-07-16 8 views
0

Je voudrais une méthode générique pour récupérer les données d'un vecteur.méthode générique de recherche?

J'ai une classe et un vecteur suivant:

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; 

(Le code complet peut être vu ici: http://codepad.org/iDD1Wme5)

Dans cet exemple, je voudrais être en mesure de récupérer des objets dans le vecteur basé sur les membres "z" ou "foo" sans avoir à écrire deux autres fonctions similaires à "FindDataById".

Est-ce possible?

+0

inséré une partie de votre code pour le rendre plus facile pour les gens à lire la question. – jalf

Répondre

4

Vous pouvez utiliser un modèle et pointeur à un membre.

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

appeler Ensuite, en utilisant, par exemple,

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

Ou, allez à l'find_if idée:

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

Et:

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)) 

Voir la réponse MSalters pour un moyen de déduire le templ mangé argument automatiquement.

+0

Le bit "Finder" ne fonctionne pas, paramètre de modèle manquant. Voir mon code comment faire Déduction d'argument de modèle. – MSalters

+0

Droite. Edité pour fournir une autre (peut-être moins élégante) façon de le faire. – Ari

+0

Vous n'avez plus besoin de la chaîne ("nom") maintenant. – MSalters

0

Vous pouvez utiliser des foncteurs et les transmettre à votre méthode de recherche. Ce que je veux dire est, définir une classe qui va surcharger bool operator(vectorElement element) et dans cet opérateur, vous choisirez la méthode comment voulez-vous rechercher les valeurs.

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

      ..... 

} 
0

Il pourrait être intéressant de jeter un oeil à std :: find définie dans l'algorithme et boost :: lambda

1

std::find_if a déjà été suggéré, mais sans un exemple de code, donc voici une version plus détaillée:

Define deux foncteurs pour identifier l'objet qui vous intéresse:

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

Et maintenant, pour rechercher des éléments où z == 42.0f, ou foo == « Bonjour tout le monde »:

std::find_if(myVector.begin(), myVector.end(), z_equals(42.0f)); 
std::find_if(myVector.begin(), myVector.end(), foo_equals("hello world")); 
0

Sans lambda de vous auriez besoin d'écrire des prédicats, ou moins instancier les:

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

Utilisation: std::find_if(..., make_member_select("x", &myClass::foo));

Questions connexes