Porównując dwa wystąpienia następującej struktury, otrzymuję błąd:
struct MyStruct1 {
MyStruct1(const MyStruct2 &_my_struct_2, const int _an_int = -1) :
my_struct_2(_my_struct_2),
an_int(_an_int)
{}
std::string toString() const;
MyStruct2 my_struct_2;
int an_int;
};
Błąd:
błąd C2678: binarny '==': nie znaleziono operatora, który przyjmuje lewostronny operand typu 'myproj :: MyStruct1' (lub nie ma akceptowalnej konwersji)
Czemu?
c++
struct
comparison-operators
Jonathan
źródło
źródło
struct
kątem równości? A jeśli chcesz prostego sposobu, zawsze jestmemcmp
tak długo, że twoje struktury nie zawierają wskaźnika.memcmp
kończy się niepowodzeniem z elementami niebędącymi POD (takimi jakstd::string
) i wyściełanymi strukturami.==
operatorowi - semantyki, która prawie nigdy nie jest tym, czego szukamy . (I nie zapewniają możliwości zastąpienia go, więc w końcu musisz użyć funkcji członkowskiej). Znane mi języki „nowoczesne” również nie zapewniają semantyki wartości, więc jesteś zmuszony używać wskaźników, nawet jeśli nie są one odpowiednie.operator=
(nawet jeśli często robi źle) ze względu na zgodność z C. Zgodność z C nie wymagaoperator==
jednak. Ogólnie wolę to, co robi C ++, od tego, co robi Java. (Nie znam C #, więc może to lepiej.)= default
!C ++ 20 wprowadził domyślne porównania, zwane także „statkiem kosmicznym”
operator<=>
, które pozwalają na żądanie operatorów wygenerowanych przez kompilator<
/<=
/==
/!=
/>=
/ i / lub>
z oczywistą / naiwną (?) Implementacją ...... ale możesz to dostosować do bardziej skomplikowanych sytuacji (omówionych poniżej). Zobacz tutaj propozycję językową, która zawiera uzasadnienia i dyskusję. Ta odpowiedź pozostaje aktualna dla C ++ 17 i wcześniejszych oraz dla wglądu w to, kiedy należy dostosować implementację
operator<=>
....Może wydawać się trochę nieprzydatne dla C ++, jeśli wcześniej tego nie ujednolicono, ale często struktury / klasy mają pewne elementy składowe danych do wykluczenia z porównania (np. Liczniki, wyniki w pamięci podręcznej, pojemność kontenera, kod powodzenia / błędu ostatniej operacji, kursory), ponieważ a także decyzje dotyczące niezliczonych rzeczy, w tym między innymi:
int
elementu członkowskiego może bardzo szybko wyeliminować 99% nierównych obiektów, podczas gdy elementmap<string,string>
członkowski może często mieć identyczne wpisy i być stosunkowo drogi do porównania - jeśli wartości są ładowane w czasie wykonywania, programista może mieć wgląd w kompilator nie możevector
,list
), a jeśli tak, to czy to jest ok, aby posortować je na miejscu przed porównaniem porównaniu z użyciem dodatkowej pamięci do sortowania tymczasowych za każdym razem odbywa się porównanieunion
do porównaniaoperator==
(ale mogą miećcompare()
luboperator<
lubstr()
lub pobierające ...)Więc miło jest mieć błąd, dopóki nie zastanowisz się wyraźnie, co powinno oznaczać porównanie dla twojej konkretnej struktury, zamiast pozwolić mu się skompilować, ale nie dać ci znaczącego wyniku w czasie wykonywania .
Wszystko to powiedziawszy, byłoby dobrze, gdyby C ++ pozwolił ci powiedzieć,
bool operator==() const = default;
kiedy zdecydowałeś, że „naiwny”==
test członka po członku jest w porządku. To samo dotyczy!=
. Podane wielu członków / zasady, „default”<
,<=
,>
, i>=
implementacje wydają się beznadziejne chociaż - kaskadowych na podstawie kolejności deklaracji jest możliwe, ale bardzo mało prawdopodobne, aby to, co chciał, biorąc pod uwagę sprzeczne imperatywy dla państw zamawiającego (podstawy bycia koniecznie przed członkami, grupowanie przez dostępność, budowa / zniszczenie przed zależnym użyciem). Aby być bardziej użytecznym, C ++ potrzebowałby nowego systemu adnotacji składowych / bazowych danych, który kierowałby wyborami - byłoby to jednak świetne rozwiązanie w standardzie, idealnie w połączeniu z generowaniem kodu zdefiniowanego przez użytkownika w oparciu o AST ... Oczekuję to'Typowa implementacja operatorów równości
Wiarygodna implementacja
Jest prawdopodobne , że rozsądne i efektywne wdrożenie będzie:
Zauważ, że to należy przedsięwziąć
operator==
dlaMyStruct2
zbyt.Implikacje tej implementacji i alternatywy są omówione poniżej w części Omówienie szczegółów dotyczących Twojego MyStruct1 .
Spójne podejście do ==, <,> <= itd
Łatwo jest wykorzystać
std::tuple
operatory porównania, aby porównać własne instancje klas - po prostu użyj ichstd::tie
do utworzenia krotek odwołań do pól w żądanej kolejności porównania. Uogólniam mój przykład stąd :Kiedy „posiadasz” (tj. Możesz edytować, czynnik z bibliotekami firmowymi i zewnętrznymi) klasę, którą chcesz porównać, a zwłaszcza z gotowością C ++ 14 do wywnioskowania typu zwracanego funkcji z
return
instrukcji, często przyjemniej jest dodać „ powiąż funkcję składową z klasą, którą chcesz porównać:Następnie powyższe porównania upraszczają się do:
Jeśli chcesz mieć pełniejszy zestaw operatorów porównania, proponuję operatory wzmocnienia (szukaj
less_than_comparable
). Jeśli z jakiegoś powodu jest to nieodpowiednie, pomysł obsługi makr (online) może ci się spodobać lub nie :... które można następnie wykorzystać a la ...
(C ++ 14 wersja z powiązanymi członkami tutaj )
Omówienie specyfiki Twojego MyStruct1
Istnieją konsekwencje wyboru zapewnienia wolnostojącego kontra członka
operator==()
...Realizacja wolnostojąca
Masz interesującą decyzję do podjęcia. Ponieważ twoja klasa może być niejawnie skonstruowana z a
MyStruct2
,bool operator==(const MyStruct2& lhs, const MyStruct2& rhs)
funkcja wolnostojąca / niebędąca składową obsługuje ...... tworząc najpierw tymczasowy plik
MyStruct1
frommy_myStruct2
, a następnie wykonując porównanie. To na pewno pozostawiłobyMyStruct1::an_int
ustawienie domyślnej wartości parametru konstruktora wynoszącej-1
. W zależności od tego, czy uwzględniszan_int
porównanie w implementacji youroperator==
, porównanieMyStruct1
może, ale nie musi, równe a,MyStruct2
które samo jest równe elementowiMyStruct1
'smy_struct_2
! Ponadto utworzenie tymczasowegoMyStruct1
może być bardzo nieefektywną operacją, ponieważ wymaga skopiowania istniejącegomy_struct2
elementu do tymczasowego, tylko po to, aby go wyrzucić po porównaniu. (Oczywiście można zapobiec tej niejawnej konstrukcjiMyStruct1
s dla porównania, tworząc ten konstruktorexplicit
lub usuwając domyślną wartość foran_int
.)Implementacja członka
Jeśli chcesz uniknąć niejawnej konstrukcji a
MyStruct1
z aMyStruct2
, uczyń z operatora porównania funkcję składową :Zwróć uwagę, że
const
słowo kluczowe - potrzebne tylko do implementacji składowej - informuje kompilator, że porównywanie obiektów ich nie modyfikuje, więc może być dozwolone naconst
obiektach.Porównanie widocznych reprezentacji
Czasami najłatwiejszym sposobem uzyskania takiego porównania jest ...
... co często jest też bardzo drogie - te
string
boleśnie stworzone, aby je wyrzucić! W przypadku typów z wartościami zmiennoprzecinkowymi porównywanie widocznych reprezentacji oznacza, że liczba wyświetlanych cyfr określa tolerancję, w ramach której prawie równe wartości są traktowane jako równe podczas porównania.źródło
int cmp(x, y)
lubcompare
funkcja powrocie ujemną wartośćx < y
, 0 dla równości i dodatnią wartośćx > y
służy jako podstawa do<
,>
,<=
,>=
,==
, i!=
; bardzo łatwo jest użyć CRTP do wstrzyknięcia wszystkich tych operatorów do klasy. Jestem pewien, że opublikowałem implementację w starej odpowiedzi, ale nie mogłem jej szybko znaleźć.>
, jak<=
i>=
pod względem<
. Można by też zaimplementować==
i w!=
ten sposób, ale myślę, że zazwyczaj nie byłaby to bardzo wydajna implementacja. Byłoby miło, gdyby do tego wszystkiego nie był potrzebny żaden CRTP ani inne sztuczki, ale standard po prostu nakazałby automatyczne generowanie tych operatorów, jeśli nie zostałyby wyraźnie zdefiniowane przez użytkownika i<
są zdefiniowane.==
i!=
może nie być efektywnie wyrażone za pomocą<
tego, że użycie porównania do wszystkiego jest powszechne. „Byłoby miło, gdyby nie CRTP lub inne sztuczki byłby potrzebny” - być może, ale wtedy CRTP mogą być łatwo wykorzystane do generowania wiele innych operatorów (np bitowe|
,&
,^
z|=
,&=
a^=
,+
-
*
/
%
od ich formy cesji; binarny-
z jednoargumentowego negacji i+
) - tak wiele potencjalnie przydatnych odmian tego tematu, że samo zapewnienie funkcji językowej dla jednego dość dowolnego fragmentu tego nie jest szczególnie eleganckie.std::tie
do porównania wielu członków?Musisz wyraźnie zdefiniować
operator ==
dlaMyStruct1
.Teraz porównanie == jest legalne dla 2 takich obiektów.
źródło
Zaczynając w C ++ 20, powinno być możliwe, aby dodać pełny zestaw operatorów porównania (domyślne
==
,<=
etc.) do klasy deklarując domyślny trójdrożny operator porównania ( „statek kosmiczny” operator), jak poniżej:W przypadku zgodnego kompilatora C ++ 20 dodanie tego wiersza do MyStruct1 i MyStruct2 może wystarczyć, aby umożliwić porównania równości, zakładając, że definicja MyStruct2 jest zgodna.
źródło
Porównanie nie działa na strukturach w C lub C ++. Zamiast tego porównaj według pól.
źródło
Domyślnie struktury nie mają
==
operatora. Będziesz musiał napisać własną implementację:źródło
Po wyjęciu z pudełka operator == działa tylko dla prymitywów. Aby kod działał, musisz przeciążyć operator == dla swojej struktury.
źródło
Ponieważ nie napisałeś operatora porównania dla swojej struktury. Kompilator nie generuje tego dla Ciebie, więc jeśli chcesz porównania, musisz napisać to sam.
źródło