2017-09-27 15 views
10

Zwykle, kiedy robię std :: find, postawię predykat jako trzeci argument, ale tym razem pomyślałem, że zrobię to inaczej, nie wiem. t zrozumieć, dlaczego to nie działa.Dlaczego nie można tego std :: znaleźć porównaj te obiekty?

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

binarny "==" żaden operator znalezione, które zajmuje leworęcznego operand typu RenderJob (lub nie ma akceptowalne konwersji)

Edit :: Dobrze dzięki za odpowiedzi . Oto kilka przykładów, dlaczego nie

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

    std::vector<RenderJob> renderJobs; 

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

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

jeszcze prostsze jako ilustracja:

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. 

Gdyby było na odwrót:

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

W twoich przykładów nie można zrobić '* Constit == foo2' lub' * pToRenderJob == foo2' ponieważ operator == '' nie jest zadeklarowana, aby umożliwić 'const' lewy argument stać' * this' . Byłoby tak samo, gdyby klasa miała funkcję 'void f();' - nie można było zrobić 'constit-> f()' lub 'pToRenderJob-> f()'. Ale jeśli zmienisz tę funkcję na "void f() const;", obie te rzeczy będą w porządku. – aschepler

+0

Dzięki, że wiele zasad powoli ustawienie w – Zebrafish

+0

Należy również definiuje 'renderJob_ID' wewnątrz swojej klasie.' Int renderJob_ID {} ​​'. Pozostawienie niezainicjowanego obiektu to przedwczesna optymalizacja. W przykładzie foo.renderJob_ID i foo.renderJob_ID mieć wartość nieokreśloną * * a jeśli zadeklarować 'std :: vector renderJobs (10)' stworzyć wektor 10 'renderJobs', wszystko to 10 obiektów będzie miał ich renderJob_ID trzyma * nieokreślona wartość *. Twój kod nie będzie działał, nawet po dodaniu const do argumentu operator ==. – Oliv

Odpowiedz

14

Zostawiłeś swoje const kwalifikatorów off.

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

Tak, dziękuję. W szczególności const RenderJob, nie ten po funkcji. Nie rozumiem tego jednak, mogę je samemu porównać ze względu na operatora == przeciążenie, czy std :: find po prostu nie użyje funkcji operatora ==? – Zebrafish

+4

Obie powinny być stałe. Gdy kompilator szuka operatora na danych stałych, odmówi wzięcia pod uwagę operatorów, którzy nie gwarantują zachowania stałego. –

+0

Teraz rozumiem, ale nadal, w moim dalszym przykładzie w pytaniu, prawa strona nie jest stała i dlatego pomyślałem, że powinienem wywołać operatora niestanowiącego const ==, chyba że oczywiście istnieje problem z porównywaniem const i niestały. – Zebrafish

5

Wygląda mi na problem z poprawnością konstelacji. Spróbuj coś takiego zamiast:

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

Doing porównania bardziej pracował bo były tylko przejazdem zwykłe przedmioty, które nie były uzupełnienia tymczasowe, ani nie były const kwalifikacje. Przy std::find funkcja porównania będzie (przynajmniej zwykle) odbierała odwołanie do obiektu w kolekcji (która zwykle będzie miała kwalifikację stałą), więc musi być w stanie odebrać referencję o stałej wartości.

+1

O, widzę, zadziałało. Ale sam mogłem je porównać. Czy funkcja porównania w std :: find nie używa funkcji operatora ==? – Zebrafish

+1

@Zebrafish 'find' pobiera wartość do porównania przez odniesienie do stałej. –

3

Ale to nadal nie ma sensu, w powyższym przykładzie, prawa strona jest foo2, który nie jest stały, który powinien udać się do nieprzestrzegania constoperator==. Chyba że istnieje ogólna zasada, że ​​nie można porównywać wartości const i non const.

W języku nie ma reguły, że obiekty const i inne niż const nie mogą być porównywane. Musisz się upewnić, że można je porównywać, używając odpowiednich kwalifikatorów const.

Linia

*pToRenderJob == foo2; 

jest równoważna

pToRenderJob->operator==(foo2); 

to nie zadziała, ponieważ pToRenderJob nie może być używany do wywołania funkcji const niebędącą użytkownika. foo2 nie jest tutaj problemem.

Jeśli używasz

foo2 == *pToRenderJob 

jest to równoważne

foo2.operator==(*pToRenderJob) 

Jest to również problem, ponieważ argument funkcji jest const obiektu w czasie, gdy funkcja oczekuje niebędącą const odniesienia. Ponownie, foo2 nie jest problemem.

dokonującej Funkcja A const funkcję Członka i czyni argument const odniesienia daje pewność, że wszystkie kombinacje const i nie- const obiektów po obu stronach operatora może być stosowany bez żadnego problemu.

+0

To jest bardzo interesujące, więc w * pToRenderJob == foo2, które działało, gdy zrobiłem rzeczywistą funkcję const. Bardzo ciekawe i subtelne zasady. – Zebrafish

+0

@Zebrafish. Przyzwyczajenie się do tych zasad zajmuje trochę czasu, ale poza tym, dzięki głębszemu zrozumieniu języka, zasady zaczynają mieć sens. –

Powiązane problemy