2017-09-27 7 views
10

Habituellement quand je fais un std :: find je mets un prédicat comme troisième argument, mais cette fois je pensais que je le ferais différemment, je ne le fais pas Je ne comprends pas pourquoi ça ne marche pas.Pourquoi std :: find ne peut-il pas comparer ces objets?

#include <iostream> 
#include <vector> 
#include <algorithm> 

struct RenderJob 
{ 
    RenderJob() {}; 
    int renderJob_ID; 
    bool operator==(RenderJob& rhs) { return rhs.renderJob_ID == this->renderJob_ID; } 
}; 

int main() 
{ 
    RenderJob foo; 
    RenderJob foo2; 
    foo == foo2; // Works 

    std::vector<RenderJob> renderJobs; 

    std::find(renderJobs.begin(), renderJobs.end(), foo); // Doesn't work 
} 

binaire "==" aucun opérateur trouvé qui prend un opérande à gauche de de type RenderJob (ou il n'y a pas de conversion acceptable)

:: Modifier Eh bien merci pour les réponses . Voici quelques exemples des raisons pour lesquelles il ne

RenderJob foo; 
    RenderJob foo2; 
    foo == foo2; // Works 

    std::vector<RenderJob> renderJobs; 

    std::vector<RenderJob>::const_iterator constit = renderJobs.begin(); 

    *constit == foo2; // Doesn't work 

Encore plus simple à titre d'illustration:

const RenderJob* pToRenderJob; 

*pToRenderJob == foo2; // This fails because the pointed to 
         // object is const, and cannot call the 
         // operator== function because the actual function 
         // definition is not const. 

Si elle était l'inverse:

foo2 == *pToRenderJob; // This would fail because the 
         // operator==(RenderJob&) the actual argument 
         // is not const. Very subtle rules 
+0

Dans vos exemples, vous ne pouvez pas faire '* constit == foo2' ou' * pToRenderJob == foo2' car l'opérateur '==' n'est pas déclaré pour permettre à un opérande 'const' gauche de devenir' * this' . Ce serait la même chose si la classe avait une fonction 'void f();' - vous ne pourriez pas faire 'constit-> f()' ou 'pToRenderJob-> f()'. Mais si vous changez cette fonction en 'void f() const;', les deux seraient bien. – aschepler

+0

Merci, les nombreuses règles se mettent en place lentement. – Zebrafish

+0

Vous devez également définir 'renderJob_ID' dans votre classe:' int renderJob_ID {} ​​'. Laisser un objet non initialisé est une optimisation prématurée. Dans votre exemple, foo.renderJob_ID et foo.renderJob_ID ont * une valeur indéterminée * et si vous déclarez 'std :: vector renderJobs (10)' pour créer un vecteur de 10 'renderJobs', tous ces 10 objets auront leur renderJob_ID contenant un * valeur indéterminée *. Donc, votre code continuera à ne pas fonctionner, même après avoir ajouté const à l'opérateur == argument. – Oliv

Répondre

14

Vous avez quitté vos const qualifiés au large.

bool operator==(const RenderJob& rhs) const { ... } 
+2

Oui, merci. Particulièrement le const RenderJob, pas celui après la fonction. Je ne comprends pas cela, je peux les comparer moi-même à cause de la surcharge de l'opérateur ==, std :: find n'utilise-t-il pas la fonction operator ==? – Zebrafish

+4

Les deux devraient être const. Lorsque le compilateur recherche un opérateur sur les données const, il refuse de considérer les opérateurs qui ne garantissent pas le comportement const. –

+0

Je comprends maintenant, mais encore, dans mon autre exemple dans la question, le côté droit est non const et donc je pensais que je devrais appeler l'opérateur non-const ==, à moins bien sûr qu'il y ait un problème généralement avec const et non-const. – Zebrafish

5

Cela me semble être un problème de const-exactitude. Essayez quelque chose comme ceci:

bool operator==(RenderJob const &rhs) const { 
    return rhs.renderJob_ID == this->renderJob_ID; 
} 

Faire la comparaison vous travaillé parce que vous venez de passage des objets simples qui ne sont pas temporaires, ils n'étaient pas const qualifiés. Avec std::find, la fonction de comparaison recevra (au moins habituellement) une référence à l'objet dans la collection (qui sera normalement qualifiée const), elle doit donc pouvoir recevoir une référence const-qualifiée.

+1

Oh, je vois, ça a marché. Mais, j'ai été capable de les comparer moi-même. Est-ce que la fonction de comparaison dans std :: find n'utilise pas la fonction opérateur ==? – Zebrafish

+1

@Zebrafish 'find' prend la valeur à comparer avec la référence const. –

3

Mais cela ne fonctionne toujours pas de sens, dans l'exemple ci-dessus, le côté droit est foo2, ce qui est constant, ce qui devrait aller à la non constoperator==. À moins qu'il n'y ait une règle générale que const et non const ne peuvent pas être comparés.

Il n'y a pas de règle dans la langue const et ne peuvent pas être comparés non const objets. Vous devez vous assurer qu'ils peuvent être comparés en utilisant les qualificateurs const appropriés.

La ligne

*pToRenderJob == foo2; 

est équivalent à

pToRenderJob->operator==(foo2); 

qui ne fonctionne pas depuis pToRenderJob ne peut pas être utilisé pour appeler une fonction non const membre. foo2 n'est pas le problème ici.

Si vous utilisez

foo2 == *pToRenderJob 

il est équivalent à

foo2.operator==(*pToRenderJob) 

qui est aussi un problème puisque l'argument de la fonction est un objet const alors que votre fonction attend une référence non const. Encore une fois, foo2 n'est pas le problème.

Faire la fonction une fonction membre const et faisant l'argument une référence const veille à ce que toutes les combinaisons de const et des objets non const des deux côtés de l'opérateur peut être utilisé sans aucun problème.

+0

C'est très intéressant, donc dans le * pToRenderJob == foo2 qui a fonctionné quand j'ai fait la fonction actuelle const. Règles très intéressantes et subtiles. – Zebrafish

+0

@Zebrafish. Il faut un certain temps pour s'habituer à ces règles, mais plus que cela, avec une compréhension plus profonde du langage, les règles commencent à avoir du sens. –