Beim Vergleich von zwei Instanzen der folgenden Struktur wird eine Fehlermeldung angezeigt:
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;
};
Der Fehler ist:
Fehler C2678: binär '==': Es wurde kein Operator gefunden, der einen linken Operanden vom Typ 'myproj :: MyStruct1' verwendet (oder es gibt keine akzeptable Konvertierung).
Warum?
c++
struct
comparison-operators
Jonathan
quelle
quelle
struct
s auf Gleichheit vergleichen möchten ? Und wenn Sie den einfachen Weg wollen, gibt es immermemcmp
so lange, bis Ihre Strukturen keinen Zeiger enthalten.memcmp
schlägt mit Nicht-POD-Mitgliedern (wiestd::string
) und gepolsterten Strukturen fehl .==
Operator eine Semantik, die fast nie das ist, was gewünscht wird. (Und sie bieten keine Möglichkeit, sie zu überschreiben, sodass Sie am Ende eine Mitgliedsfunktion verwenden müssen.) Die "modernen" Sprachen, die ich kenne, bieten auch keine Wertesemantik, sodass Sie gezwungen sind, Zeiger zu verwenden, auch wenn sie nicht geeignet sind.operator=
aus Gründen der C-Kompatibilität eine Standardeinstellung (auch wenn dies häufig falsch ist). Für die C-Kompatibilität ist jedoch keine erforderlichoperator==
. Global bevorzuge ich, was C ++ macht, was Java macht. (Ich kenne C # nicht, also ist das vielleicht besser.)= default
sein!In C ++ 20 wurden Standardvergleiche
operator<=>
eingeführt , auch bekannt als "Raumschiff" , mit denen Sie vom Compiler generierte<
/<=
/==
/!=
/>=
/ und / oder>
Operatoren mit der offensichtlichen / naiven (?) Implementierung anfordern können ...... aber Sie können dies für kompliziertere Situationen anpassen (siehe unten). Siehe hier für die Sprache Vorschlag, die Rechtfertigungen und Diskussion enthält. Diese Antwort bleibt für C ++ 17 und frühere Versionen relevant und gibt Aufschluss darüber, wann Sie die Implementierung von
operator<=>
.... anpassen sollten .Es mag für C ++ etwas wenig hilfreich erscheinen, dies nicht bereits früher standardisiert zu haben, aber häufig müssen Strukturen / Klassen einige Datenelemente vom Vergleich ausschließen (z. B. Zähler, zwischengespeicherte Ergebnisse, Containerkapazität, Erfolg / Fehlercode der letzten Operation, Cursor) sowie Entscheidungen über unzählige Dinge zu treffen, einschließlich, aber nicht beschränkt auf:
int
Elements, kann 99% der ungleichen Objekte sehr schnell beseitigen, während einmap<string,string>
Mitglied häufig identische Einträge hat und relativ teuer zu vergleichen ist. Wenn die Werte zur Laufzeit geladen werden, hat der Programmierer möglicherweise Einblicke in die Compiler kann unmöglichvector
,list
), und wenn ja , ob es in Ordnung ist , sie an Ort und Stelle zu sortieren , bevor Vergleich vs. mit zusätzlichen Speichern zu sortieren Provisorien jedesmal , wenn ein Vergleich gemacht wirdunion
zu vergleichenoperator==
selbst implementieren (aber möglicherweisecompare()
oderoperator<
oderstr()
oder Getter haben ...)Es ist also nett, einen Fehler zu haben, bis Sie explizit darüber nachgedacht haben, was ein Vergleich für Ihre spezifische Struktur bedeuten soll, anstatt ihn kompilieren zu lassen, aber zur Laufzeit kein aussagekräftiges Ergebnis zu erzielen .
Alles in allem wäre es gut, wenn C ++ Sie sagen
bool operator==() const = default;
lassen würde, wenn Sie entschieden hätten, dass ein "naiver"==
Test von Mitglied zu Mitglied in Ordnung ist. Gleiches gilt für!=
. Gegeben mehrere Mitglieder / Basen, „default“<
,<=
,>
und>=
Implementierungen scheinen hoffnungslos obwohl - Kaskadierung auf der Grundlage der Reihenfolge der Deklaration ist möglich , aber sehr unwahrscheinlich zu sein , was gewünscht ist, da widersprüchliche Erfordernisse für das Mitglied Ordnung (Basen sind unbedingt vor Mitgliedern, die Gruppierung von Zugänglichkeit, Bau / Zerstörung vor abhängiger Nutzung). Um allgemeiner nützlich zu sein, würde C ++ ein neues Annotationssystem für Datenelemente / Basen benötigen, um die Auswahl zu leiten - das wäre jedoch eine großartige Sache im Standard, idealerweise in Verbindung mit einer AST-basierten benutzerdefinierten Codegenerierung ... Ich erwarte es'Typische Implementierung von Gleichstellungsoperatoren
Eine plausible Umsetzung
Es ist wahrscheinlich, dass eine vernünftige und effiziente Implementierung wäre:
Beachten Sie, dass dies auch ein
operator==
für benötigtMyStruct2
.Die Auswirkungen dieser Implementierung und Alternativen werden unter der Überschrift Diskussion der Besonderheiten Ihres MyStruct1 weiter unten erläutert .
Ein konsistenter Ansatz für ==, <,> <= etc.
Es ist einfach, die
std::tuple
Vergleichsoperatoren zu nutzen, um Ihre eigenen Klasseninstanzen zu vergleichen. Verwenden Siestd::tie
diese Option, um Tupel von Verweisen auf Felder in der gewünschten Vergleichsreihenfolge zu erstellen. Verallgemeinern Sie mein Beispiel von hier :Wenn Sie die Klasse, die Sie vergleichen möchten, "besitzen" (dh bearbeiten können, einen Faktor mit Unternehmens- und Drittanbieter-Bibliotheken), und insbesondere mit der Bereitschaft von C ++ 14, den Funktionsrückgabetyp aus der
return
Anweisung abzuleiten , ist es oft besser, eine " Binden Sie die Member-Funktion an die Klasse, die Sie vergleichen möchten:Dann vereinfachen sich die obigen Vergleiche zu:
Wenn Sie einen umfassenderen Satz von Vergleichsoperatoren wünschen, empfehle ich Boost-Operatoren (Suche nach
less_than_comparable
). Wenn es aus irgendeinem Grund ungeeignet ist, kann Ihnen die Idee der Unterstützung von Makros (online) gefallen oder auch nicht :... das kann dann a la verwendet werden ...
(C ++ 14 Member-Tie-Version hier )
Diskussion der Besonderheiten Ihres MyStruct1
Die Entscheidung, ein freistehendes Mitglied zu stellen, hat Auswirkungen
operator==()
...Freistehende Implementierung
Sie müssen eine interessante Entscheidung treffen. Da Ihre Klasse implizit aus a aufgebaut werden kann
MyStruct2
, würde eine freistehende / Nichtmitgliedsfunktionbool operator==(const MyStruct2& lhs, const MyStruct2& rhs)
...... indem Sie zuerst ein temporäres
MyStruct1
aus erstellenmy_myStruct2
und dann den Vergleich durchführen. Dies würde definitivMyStruct1::an_int
auf den Standardparameterwert des Konstruktors von gesetzt bleiben-1
. Je nachdem , ob Sie umfassenan_int
Vergleich in der Umsetzung Ihreroperator==
, eineMyStruct1
Kraft oder vielleicht vergleichen nicht gleich ein ,MyStruct2
dass selbst vergleicht gleich dasMyStruct1
‚smy_struct_2
Mitglied! Darüber hinaus kann das Erstellen eines temporärenMyStruct1
Elements eine sehr ineffiziente Operation sein, da das vorhandenemy_struct2
Mitglied in ein temporäres Element kopiert wird , um es nach dem Vergleich wegzuwerfen. (Natürlich können Sie diese implizite Konstruktion vonMyStruct1
s zum Vergleich verhindern, indem Sie diesen Konstruktorexplicit
erstellen oder den Standardwert für entfernenan_int
.)Implementierung der Mitglieder
Wenn Sie die implizite Konstruktion von a
MyStruct1
aus a vermeiden möchtenMyStruct2
, machen Sie den Vergleichsoperator zu einer Elementfunktion:Beachten Sie, dass das
const
Schlüsselwort - das nur für die Member-Implementierung benötigt wird - den Compiler darauf hinweist, dass das Vergleichen von Objekten diese nicht ändert und daher fürconst
Objekte zulässig sein kann.Vergleich der sichtbaren Darstellungen
Manchmal ist der einfachste Weg, um die Art von Vergleich zu erhalten, die Sie wollen, ...
... was oft auch sehr teuer ist - die sind
string
schmerzhaft geschaffen, nur um weggeworfen zu werden! Bei Typen mit Gleitkommawerten bedeutet der Vergleich sichtbarer Darstellungen, dass die Anzahl der angezeigten Ziffern die Toleranz bestimmt, innerhalb derer nahezu gleiche Werte beim Vergleich als gleich behandelt werden.quelle
int cmp(x, y)
odercompare
Funktion einen negativen Wert für die Rückführungx < y
, 0 für Gleichberechtigung und einen positiven Wert fürx > y
die Basis verwendet wird<
,>
,<=
,>=
,==
, und!=
; Es ist sehr einfach, CRTP zu verwenden, um all diese Operatoren in eine Klasse einzufügen. Ich bin sicher, dass ich die Implementierung in einer alten Antwort veröffentlicht habe, sie aber nicht schnell finden konnte.>
,<=
und>=
in Bezug auf<
. Sie könnten auch implementieren==
und!=
auf diese Weise, aber das würde in der Regel nicht eine sehr effiziente Implementierung Ich denke , sein. Es wäre schön, wenn für all dies kein CRTP oder andere Tricks erforderlich wären, aber der Standard würde nur die automatische Generierung dieser Operatoren vorschreiben, wenn dies nicht explizit vom Benutzer definiert wird und<
definiert ist.==
und!=
nicht effizient mit ausgedrückt werden könnte ,<
dass für alles , was üblich ist zu vergleichen , verwenden. „Es wäre schön, wenn kein CRTP oder andere Tricks benötigt würden“ - vielleicht, aber dann kann CRTP leicht verwendet werden , viele andere Betreiber zu generieren (zB bitweise|
,&
,^
aus|=
,&=
und^=
,+
-
*
/
%
aus deren Zuordnung Formen; binäre-
von einstellige Negation und+
) - so viele potenziell nützliche Variationen dieses Themas, dass es nicht besonders elegant ist, nur eine Sprachfunktion für ein ziemlich beliebiges Stück davon bereitzustellen.std::tie
der mehrere Mitglieder verglichen werden können?Sie müssen explizit
operator ==
für definierenMyStruct1
.Jetzt ist der == Vergleich für 2 solcher Objekte zulässig.
quelle
Beginnend in C ++ 20, sollte es möglich sein , einen vollständigen Satz von Standardvergleichsoperatoren hinzufügen (
==
,<=
usw.) zu einer Klasse von einer Erklärung der Standard - Drei-Wege - Vergleichsoperator ( „Raumschiff“ Operator), wie folgt aus :Bei einem kompatiblen C ++ 20-Compiler kann das Hinzufügen dieser Zeile zu MyStruct1 und MyStruct2 ausreichen, um Gleichheitsvergleiche zu ermöglichen, vorausgesetzt, die Definition von MyStruct2 ist kompatibel.
quelle
Der Vergleich funktioniert nicht bei Strukturen in C oder C ++. Vergleichen Sie stattdessen nach Feldern.
quelle
Standardmäßig haben Strukturen keinen
==
Operator. Sie müssen Ihre eigene Implementierung schreiben:quelle
Standardmäßig funktioniert der Operator == nur für Grundelemente. Damit Ihr Code funktioniert, müssen Sie den Operator == für Ihre Struktur überladen.
quelle
Weil Sie keinen Vergleichsoperator für Ihre Struktur geschrieben haben. Der Compiler generiert es nicht für Sie. Wenn Sie also einen Vergleich wünschen, müssen Sie es selbst schreiben.
quelle