web-dev-qa-db-fra.com

Comment utiliser std :: find / std :: find_if avec un vecteur d'objets de classe personnalisés?

J'ai une classe représentant un utilisateur appelé Nick et je veux utiliser std::find_if Dessus, où je veux trouver si le vecteur de la liste d'utilisateurs a un objet inclus avec le même nom d'utilisateur que je passe. I a fait quelques tentatives en essayant de créer un nouvel objet Nick pour le nom d'utilisateur que je veux tester et en surchargeant le == operator, puis en essayant d'utiliser find/find_if sur l'objet:

    std::vector<Nick> userlist;
    std::string username = "Nicholas";

if (std::find(userlist.begin(), userlist.end(), new Nick(username, false)) != userlist.end())) {
    std::cout << "found";
}

J'ai surchargé le == operator Donc comparer Nick == Nick2 devrait fonctionner, mais la fonction retourne error C2678: binary '==' : no operator found which takes a left-hand operand of type 'Nick' (or there is no acceptable conversion).

Voici ma classe Nick pour référence:

class Nick {
private:
    Nick() {
        username = interest = email = "";
                    is_op = false;
    };
public:
    std::string username;
    std::string interest;
    std::string email;
    bool is_op;

    Nick(std::string d_username, std::string d_interest, std::string d_email, bool d_is_op) {
        Nick();
        username = d_username;
        interest = d_interest;
        email = d_email;
        is_op = d_is_op;
    };
    Nick(std::string d_username, bool d_is_op) {
        Nick();
        username = d_username;
        is_op = d_is_op;
    };
    friend bool operator== (Nick &n1, Nick &n2) {
        return (n1.username == n2.username);
    };
    friend bool operator!= (Nick &n1, Nick &n2) {
        return !(n1 == n2);
    };
};
26
Speed

Vous devez définir l'opérateur == avec deux objets en dehors de votre classe, en tant que fonction d'outil, pas en tant que membre.

Ensuite, pour le rendre ami, mettez simplement la déclaration de la fonction dans la classe.

essayez quelque chose comme ceci:

class Nick {

public:
    friend bool operator== ( const Nick &n1, const Nick &n2);
};


bool operator== ( const Nick &n1, const Nick &n2) 
{
        return n1.username == n2.username;
}

Votre recherche devrait également ressembler à ceci:

std::find(userlist.begin(), userlist.end(), Nick(username, false) );

Pas besoin de "nouveau".

16
Nikko

Si vous utilisez C++ 0X, vous pouvez utiliser une simple expression lambda

std::string username = "Nicholas";    
std::find_if(userlist.begin(), userlist.end(), [username](Nick const& n){
    return n.username == username;
})
38
mkaes

Je sais que tu voulais surcharger le ==, mais la même chose peut facilement être faite avec un prédicat:

struct UsernameIs {
    UsernameIs( string s ) : toFind(s) { }
    bool operator() (const Nick &n)
        { return n.username == toFind; }
    string toFind;
};

int main()
{
    vector<Nick> vn(10);
    string nameToFind = "something";
    find_if(vn.begin(), vn.end(), UsernameIs(nameToFind));
}

Notez qu'en C++ 0x, vous pouvez faire la même chose avec une expression lambda de manière beaucoup plus concise.

9
Seb Holzapfel

Vous passez un pointeur sur la fonction de recherche. Déposez le nouveau:

std::find(userlist.begin(), userlist.end(), Nick(username, false))

De plus, vos opérateurs doivent accepter leurs arguments par référence const, ils ne les modifient pas.

bool operator== (const Nick &n1, const Nick &n2)
3
Benjamin Lindley

Je remarque que vous essayez d'appeler un constructeur d'un autre de cette manière:

Nick(std::string d_username, bool d_is_op) {
        Nick();
 ...

Eh bien, désolé, mais cela ne fonctionne pas. La ligne Nick() crée juste un temporaire et n'affecte pas this. Le transfert de constructeur n'est possible qu'en C++ 0x (la norme à venir)

Quant à votre problème - cette question posée il y a quelques jours à propos de binary_search couvre les mêmes motifs. La meilleure réponse est tout simplement géniale.

Restriction mystique sur std :: binary_search

HTH.

P.S. Idéalement, cela aurait dû être un commentaire, mais il est tout simplement trop verbeux

1
Armen Tsirunyan

Vous pouvez utiliser boost :: bind

std::find_if( userlist.begin(), userlist.end(),
            boost::bind( & Nick::isFound,
                         _1 ) );

implémentez simplement bool Nick :: isFound ()

Vous pouvez également passer les critères

std::find_if( userlist.begin(), userlist.end(),
              boost::bind( & Nick::compare,
                           _1,
                           nick ) );

mettre en place

bool Nick::compare( const Nick & nick )
{
    return this->username == nick.username;
}
0
Nelstaar