Warum definieren C ++ - Compiler nicht operator == und operator! =?

302

Ich bin ein großer Fan davon, den Compiler so viel Arbeit wie möglich für Sie erledigen zu lassen. Beim Schreiben einer einfachen Klasse kann der Compiler Ihnen Folgendes kostenlos zur Verfügung stellen:

  • Ein Standardkonstruktor (leer)
  • Ein Kopierkonstruktor
  • Ein Zerstörer
  • Ein Zuweisungsoperator ( operator=)

Es kann Ihnen jedoch keine Vergleichsoperatoren geben - wie operator==oder operator!=. Zum Beispiel:

class foo
{
public:
    std::string str_;
    int n_;
};

foo f1;        // Works
foo f2(f1);    // Works
foo f3;
f3 = f2;       // Works

if (f3 == f2)  // Fails
{ }

if (f3 != f2)  // Fails
{ }

Gibt es dafür einen guten Grund? Warum sollte ein Vergleich von Mitglied zu Mitglied ein Problem sein? Wenn die Klasse Speicher zuweist, möchten Sie natürlich vorsichtig sein, aber für eine einfache Klasse könnte der Compiler dies sicherlich für Sie tun?

rauben
quelle
4
Natürlich wird auch der Destruktor kostenlos zur Verfügung gestellt.
Johann Gerell
23
In einem seiner letzten Gespräche wies Alex Stepanov darauf hin, dass es ein Fehler war, keine Standardautomatik zu haben ==, genauso wie es =unter bestimmten Bedingungen eine Standardautomatikzuweisung ( ) gibt. (Das Argument über Zeiger ist inkonsistent, da die Logik sowohl für =als ==auch nicht nur für die Sekunde gilt.)
AlfC
2
@becko Es ist eines in der Reihe bei A9: youtube.com/watch?v=k-meLQaYP5Y , ich erinnere mich nicht, in welchem ​​der Gespräche. Es gibt auch einen Vorschlag, dass es seinen Weg zu C ++ 17 open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0221r0.html
alfC
1
@becko, es ist eines der ersten in der Reihe "Effiziente Programmierung mit Komponenten" oder "Programmiergespräche", beide bei A9, verfügbar auf Youtube.
alfC
1
@becko Tatsächlich gibt es unten eine Antwort, die auf Alex 'Standpunkt verweist stackoverflow.com/a/23329089/225186
alfC

Antworten:

71

Der Compiler würde nicht wissen, ob Sie einen Zeigervergleich oder einen tiefen (internen) Vergleich wünschen.

Es ist sicherer, es einfach nicht zu implementieren und den Programmierer das selbst tun zu lassen. Dann können sie alle Annahmen treffen, die sie mögen.

Mark Ingram
quelle
292
Dieses Problem hindert es nicht daran, einen Kopierer zu generieren, der ziemlich schädlich ist.
MSalters
78
Kopierkonstruktoren (und operator=) in der Regel Arbeit im gleichen Kontext wie Vergleichsoperator - das heißt, es wird erwartet , dass nach der Ausführung a = b, a == bwahr ist. Es ist auf jeden Fall sinnvoll, dass der Compiler einen Standardwert operator==mit derselben Aggregatwertsemantik wie für bereitstellt operator=. Ich vermute, dass Paercebal hier tatsächlich insofern richtig ist, als operator=(und Copy Ctor) nur aus Gründen der C-Kompatibilität bereitgestellt werden und sie die Situation nicht verschlimmern wollten.
Pavel Minaev
46
-1. Natürlich möchten Sie einen tiefen Vergleich, wenn der Programmierer einen Zeigervergleich wollte, würde er schreiben (& f1 == & f2)
Viktor Sehr
62
Viktor, ich schlage vor, Sie überdenken Ihre Antwort. Wenn die Klasse Foo einen Balken * enthält, wie würde der Compiler dann wissen, ob Foo :: operator == die Adresse des Balkens * oder den Inhalt des Balkens vergleichen möchte?
Mark Ingram
46
@Mark: Wenn es einen Zeiger enthält, ist ein Vergleich der Zeigerwerte sinnvoll. Wenn es einen Wert enthält, ist ein Vergleich der Werte sinnvoll. In Ausnahmefällen kann der Programmierer überschreiben. Dies ist genau so, als würde die Sprache einen Vergleich zwischen Ints und Zeiger-zu-Ints implementieren.
Eamon Nerbonne
317

Das Argument, dass der Compiler, wenn er einen Standardkopierkonstruktor bereitstellen kann, einen ähnlichen Standard bereitstellen kann, operator==()ist in gewissem Maße sinnvoll. Ich denke, dass der Grund für die Entscheidung, keinen vom Compiler generierten Standard für diesen Operator bereitzustellen, durch die Aussagen von Stroustrup zum Standardkopierkonstruktor in "Das Design und die Entwicklung von C ++" (Abschnitt 11.4.1 - Kontrolle des Kopierens) erraten werden kann. ::

Ich persönlich halte es für bedauerlich, dass Kopiervorgänge standardmäßig definiert sind, und ich verbiete das Kopieren von Objekten vieler meiner Klassen. C ++ hat jedoch seine Standardzuweisungs- und Kopierkonstruktoren von C geerbt und sie werden häufig verwendet.

Anstelle von "Warum hat C ++ keine Standardeinstellung operator==()?" Sollte die Frage lauten: "Warum hat C ++ eine Standardzuweisung und einen Kopierkonstruktor?". Die Antwort lautete, dass diese Elemente von Stroustrup aus Gründen der Abwärtskompatibilität mit C nur ungern aufgenommen wurden (wahrscheinlich die Ursache für die meisten Warzen von C ++, aber wahrscheinlich auch der Hauptgrund für die Popularität von C ++).

Für meine eigenen Zwecke enthält das Snippet, das ich für neue Klassen verwende, in meiner IDE Deklarationen für einen privaten Zuweisungsoperator und einen Kopierkonstruktor, sodass ich beim Erstellen einer neuen Klasse keine Standardzuweisungen und Kopiervorgänge erhalte. Ich muss die Deklaration explizit entfernen dieser Operationen aus dem private:Abschnitt, wenn ich möchte, dass der Compiler sie für mich generieren kann.

Michael Burr
quelle
29
Gute Antwort. Ich möchte nur darauf hinweisen, dass Sie in C ++ 11 den Zuweisungsoperator und den Kopierkonstruktor nicht privat machen, sondern vollständig entfernen können: Foo(const Foo&) = delete; // no copy constructorundFoo& Foo=(const Foo&) = delete; // no assignment operator
karadoc
9
"C ++ hat jedoch seine Standardzuweisung und Kopierkonstruktoren von C geerbt." Dies bedeutet nicht, dass Sie ALLE C ++ - Typen auf diese Weise erstellen müssen. Sie hätten dies nur auf einfache alte PODs beschränken sollen, nur auf die Typen, die bereits in C sind, nicht mehr.
Heilige
3
Ich kann sicherlich verstehen, warum C ++ diese Verhaltensweisen für geerbt hat struct, aber ich wünsche mir, dass es classsich anders (und vernünftig) verhält. Dabei hätte es auch einen bedeutenderen Unterschied zwischen structund classneben dem Standardzugriff gegeben.
Jamesdlin
@jamesdlin Wenn Sie eine Regel möchten, ist es am sinnvollsten, die implizite Deklaration und Definition von ctors und die Zuweisung zu deaktivieren, wenn ein dtor deklariert wird.
Deduplikator
1
Ich sehe immer noch keinen Schaden darin, dass der Programmierer dem Compiler explizit befiehlt, eine zu erstellen operator==. Zu diesem Zeitpunkt ist es nur Syntaxzucker für einen Kesselplattencode. Wenn Sie befürchten, dass der Programmierer auf diese Weise einen Zeiger zwischen Klassenfeldern übersieht, können Sie eine Bedingung hinzufügen, dass er nur für primitive Typen und Objekte funktioniert, die selbst Gleichheitsoperatoren haben. Es gibt jedoch keinen Grund, dies vollständig zu verbieten.
NO_NAME
93

Selbst in C ++ 20 generiert der Compiler nicht implizit operator==für Sie

struct foo
{
    std::string str;
    int n;
};

assert(foo{"Anton", 1} == foo{"Anton", 1}); // ill-formed

Seit C ++ 20 können Sie jedoch explizit Standardwerte == festlegen :

struct foo
{
    std::string str;
    int n;

    // either member form
    bool operator==(foo const&) const = default;
    // ... or friend form
    friend bool operator==(foo const&, foo const&) = default;
};

Die Standardeinstellung ==erfolgt in Bezug auf die Mitglieder ==(auf die gleiche Weise wie der Standardkopierkonstruktor in Bezug auf die Mitglieder ). Die neuen Regeln bieten auch die erwartete Beziehung zwischen ==und !=. Zum Beispiel kann ich mit der obigen Erklärung beides schreiben:

assert(foo{"Anton", 1} == foo{"Anton", 1}); // ok!
assert(foo{"Anton", 1} != foo{"Anton", 2}); // ok!

Diese spezielle Funktion (Standardeinstellung operator==und Symmetrie zwischen ==und !=) stammt aus einem Vorschlag , der Teil der umfassenderen Sprachfunktion war operator<=>.

Anton Savin
quelle
Wissen Sie, ob es ein neueres Update dazu gibt? Wird es in C ++ 17 verfügbar sein?
dcmm88
3
@ dcmm88 Leider ist es in C ++ 17 nicht verfügbar. Ich habe die Antwort aktualisiert.
Anton Savin
2
Ein modifizierter Vorschlag, der dasselbe erlaubt (außer der Kurzform), wird allerdings in C ++ 20 sein :)
Rakete1111
Im Grunde muss man also angeben = default, was nicht standardmäßig erstellt wird, oder? Es klingt für mich wie Oxymoron ("explizite Standardeinstellung").
Artin
@artin Es ist sinnvoll, neue Funktionen zur Sprache hinzuzufügen, um die vorhandene Implementierung nicht zu beschädigen. Das Hinzufügen neuer Bibliotheksstandards oder neuer Funktionen des Compilers ist eine Sache. Das Hinzufügen neuer Mitgliedsfunktionen, wo sie vorher nicht existierten, ist eine ganz andere Geschichte. Um Ihr Projekt vor Fehlern zu schützen, wäre viel mehr Aufwand erforderlich. Ich persönlich würde es vorziehen, wenn das Compiler-Flag zwischen explizitem und implizitem Standard wechselt. Sie erstellen ein Projekt aus einem älteren C ++ - Standard und verwenden den expliziten Standard des Compiler-Flags. Sie aktualisieren den Compiler bereits, sodass Sie ihn ordnungsgemäß konfigurieren sollten. Für neue Projekte machen Sie es implizit.
Maciej Załucki
44

IMHO gibt es keinen "guten" Grund. Der Grund, warum es so viele Menschen gibt, die dieser Entwurfsentscheidung zustimmen, ist, dass sie nicht gelernt haben, die Kraft der wertebasierten Semantik zu beherrschen. Die Benutzer müssen viele benutzerdefinierte Kopierkonstruktoren, Vergleichsoperatoren und Destruktoren schreiben, da sie in ihrer Implementierung Rohzeiger verwenden.

Bei Verwendung geeigneter intelligenter Zeiger (wie std :: shared_ptr) ist der Standardkopierkonstruktor normalerweise in Ordnung, und die offensichtliche Implementierung des hypothetischen Standardvergleichsoperators wäre ebenso in Ordnung.

alexk7
quelle
39

Es wurde geantwortet, dass C ++ nicht == getan hat, weil C nicht getan hat, und hier ist, warum C nur Standard = aber kein == an erster Stelle bereitstellt. C wollte es einfach halten: C implementiert = von memcpy; == kann jedoch aufgrund des Auffüllens nicht von memcmp implementiert werden. Da das Auffüllen nicht initialisiert wird, gibt memcmp an, dass sie unterschiedlich sind, obwohl sie gleich sind. Das gleiche Problem besteht für leere Klassen: memcmp gibt an, dass sie unterschiedlich sind, da die Größe leerer Klassen nicht Null ist. Es kann von oben zu sehen, dass die Umsetzung == ist komplizierter als = in C einige Code Implementierung Beispiel in Bezug auf diese. Ihre Korrektur wird geschätzt, wenn ich falsch liege.

Rio Wing
quelle
6
C ++ verwendet memcpy nicht für operator=- das würde nur für POD-Typen funktionieren, aber C ++ bietet auch einen Standard operator=für Nicht-POD-Typen.
Flexo
2
Ja, C ++ implementiert = auf eine ausgefeiltere Art und Weise. Es scheint, dass C gerade implementiert wurde = mit einem einfachen Memcpy.
Rio Wing
Der Inhalt dieser Antwort sollte mit Michaels zusammengestellt werden. Er korrigiert die Frage, dann beantwortet diese sie.
Sgene9
27

In diesem Video spricht Alex Stepanov, der Schöpfer von STL, genau diese Frage gegen 13:00 Uhr an. Zusammenfassend argumentiert er, nachdem er die Entwicklung von C ++ beobachtet hat, dass:

  • Es ist bedauerlich, dass == und! = Nicht implizit deklariert werden (und Bjarne stimmt ihm zu). Eine korrekte Sprache sollte diese Dinge für Sie bereithalten (er schlägt weiter vor, dass Sie nicht in der Lage sein sollten, ein ! = Zu definieren , das die Semantik von == bricht ).
  • Der Grund, warum dies der Fall ist, hat seine Wurzeln (wie viele C ++ - Probleme) in C. Dort wird der Zuweisungsoperator implizit mit einer bitweisen Zuweisung definiert, aber das würde für == nicht funktionieren . Eine ausführlichere Erklärung finden Sie in diesem Artikel von Bjarne Stroustrup.
  • In der Folgefrage, warum dann kein Mitglied im Vergleich verwendet wurde , sagt er etwas Erstaunliches : C war eine Art einheimische Sprache, und der Typ, der diese Dinge für Ritchie implementierte, sagte ihm, er finde es schwierig, dies zu implementieren!

Er sagt dann, dass in (ferner) Zukunft == und ! = Implizit generiert werden.

Nikos Athanasiou
quelle
2
Es scheint, als ob diese ferne Zukunft weder 2017 noch 18 oder 19 sein wird.
Nun
18

C ++ 20 bietet eine Möglichkeit, einen Standardvergleichsoperator einfach zu implementieren.

Beispiel von cppreference.com :

class Point {
    int x;
    int y;
public:
    auto operator<=>(const Point&) const = default;
    // ... non-comparison functions ...
};

// compiler implicitly declares operator== and all four relational operators work
Point pt1, pt2;
if (pt1 == pt2) { /*...*/ } // ok, calls implicit Point::operator==
std::set<Point> s; // ok
s.insert(pt1); // ok
if (pt1 <= pt2) { /*...*/ } // ok, makes only a single call to Point::operator<=>
vll
quelle
4
Ich bin überrascht, dass sie Pointals Beispiel für eine Bestelloperation verwendet wurden, da es keine vernünftige Standardmethode gibt, um zwei Punkte mit xund yKoordinaten zu bestellen ...
Pipe
4
@pipe Wenn es Ihnen egal ist, in welcher Reihenfolge sich die Elemente befinden, ist die Verwendung des Standardoperators sinnvoll. Zum Beispiel könnten Sie verwenden , std::setdass alle Punkte zu machen sind einzigartig, und std::setverwenden operator<nur.
vll
Über den Rückgabetyp auto: Können wir in diesem Fall immer davon ausgehen, dass er std::strong_orderingvon stammt #include <compare>?
Kevinarpe
1
@kevinarpe Der Rückgabetyp ist std::common_comparison_category_t, der für diese Klasse zur Standardreihenfolge ( std::strong_ordering) wird.
11.
15

Es ist nicht möglich, Standard zu definieren ==, aber Sie können Standard definieren, !=über ==den Sie sich normalerweise selbst definieren sollten. Dazu sollten Sie folgende Dinge tun:

#include <utility>
using namespace std::rel_ops;
...

class FooClass
{
public:
  bool operator== (const FooClass& other) const {
  // ...
  }
};

Weitere Informationen finden Sie unter http://www.cplusplus.com/reference/std/utility/rel_ops/ .

Wenn Sie definieren operator< , können außerdem Operatoren für <=,>,> = bei der Verwendung daraus abgeleitet werden std::rel_ops.

Bei der Verwendung sollten Sie jedoch vorsichtig sein, std::rel_opsda Vergleichsoperatoren für die Typen abgeleitet werden können, für die Sie nicht erwartet werden.

Die bevorzugte Methode, um verwandte Operatoren von einfachen abzuleiten, ist die Verwendung von boost :: -Operatoren .

Der in Boost verwendete Ansatz ist besser, da er die Verwendung des Operators für die Klasse definiert, die Sie nur möchten, nicht für alle Klassen im Gültigkeitsbereich.

Sie können auch "+" aus "+ =", - aus "- =" usw. generieren (siehe vollständige Liste hier )

sergtk
quelle
Ich habe !=nach dem Schreiben des ==Operators keine Standardeinstellung erhalten . Oder ich tat es, aber es fehlte an constNess. Musste es auch selbst schreiben und alles war gut.
John
Sie können mit Beständigkeit spielen, um die erforderlichen Ergebnisse zu erzielen. Ohne Code ist es schwierig zu sagen, was daran falsch ist.
Sergtk
2
Es gibt einen Grund, der rel_opsin C ++ 20 veraltet ist: weil es nicht funktioniert , zumindest nicht überall und schon gar nicht konsequent. Es gibt keinen zuverlässigen Weg sort_decreasing()zum Kompilieren. Auf der anderen Seite funktioniert Boost.Operators und hat immer funktioniert.
Barry
10

C ++ 0x hat einen Vorschlag für Standardfunktionen. Man könnte also sagen, default operator==; wir haben gelernt, dass es hilfreich ist, diese Dinge explizit zu machen.

MSalters
quelle
3
Ich dachte, dass nur die "speziellen Elementfunktionen" (Standardkonstruktor, Kopierkonstruktor, Zuweisungsoperator und Destruktor) explizit als Standard festgelegt werden könnten. Haben sie dies auf einige andere Betreiber ausgedehnt?
Michael Burr
4
Der Verschiebungskonstruktor kann auch standardmäßig verwendet werden, aber ich denke nicht, dass dies zutrifft operator==. Welches ist schade.
Pavel Minaev
5

Konzeptionell ist es nicht einfach, Gleichheit zu definieren. Selbst für POD-Daten könnte man argumentieren, dass selbst wenn die Felder gleich sind, es sich jedoch um ein anderes Objekt (an einer anderen Adresse) handelt, es nicht unbedingt gleich ist. Dies hängt tatsächlich von der Verwendung des Bedieners ab. Leider ist Ihr Compiler nicht psychisch und kann daraus nicht schließen.

Außerdem sind Standardfunktionen hervorragende Möglichkeiten, sich in den Fuß zu schießen. Die von Ihnen beschriebenen Standardeinstellungen dienen im Wesentlichen der Kompatibilität mit POD-Strukturen. Sie verursachen jedoch mehr als genug Chaos, wenn Entwickler sie oder die Semantik der Standardimplementierungen vergessen.

Paul de Vrieze
quelle
10
Es gibt keine Mehrdeutigkeit für POD-Strukturen - sie sollten sich genauso verhalten wie jeder andere POD-Typ, dh Wertgleichheit (statt Referenzgleichheit). Eine, intdie über copy ctor von einer anderen erstellt wurde, entspricht der, aus der sie erstellt wurde. Für ein structvon zwei intFeldern ist es nur logisch, genau auf die gleiche Weise zu arbeiten.
Pavel Minaev
1
@mgiuca: Ich sehe eine beträchtliche Nützlichkeit für eine universelle Äquivalenzbeziehung, die es ermöglichen würde, jeden Typ, der sich als Wert verhält, als Schlüssel in einem Wörterbuch oder einer ähnlichen Sammlung zu verwenden. Solche Sammlungen können sich jedoch ohne eine garantierte reflexive Äquivalenzbeziehung nicht sinnvoll verhalten. IMHO wäre die beste Lösung, einen neuen Operator zu definieren, den alle eingebauten Typen sinnvoll implementieren könnten, und einige neue Zeigertypen zu definieren, die den vorhandenen ähnlich sind, mit der Ausnahme, dass einige Gleichheit als Referenzäquivalenz definieren würden, während andere mit dem Ziel verketten würden Äquivalenzoperator.
Supercat
1
@supercat Analog könnten Sie für den +Operator fast das gleiche Argument vorbringen, da es für Floats nicht assoziativ ist. das heißt (x + y) + z! = x + (y + z)aufgrund der Art und Weise, wie FP-Rundungen auftreten. (Dies ist ==wahrscheinlich ein weitaus schlimmeres Problem als weil es für normale numerische Werte gilt.) Sie könnten vorschlagen, einen neuen Additionsoperator hinzuzufügen, der für alle numerischen Typen (sogar int) funktioniert und fast genau der gleiche ist, +aber assoziativ ( irgendwie). Aber dann würden Sie der Sprache Aufblähung und Verwirrung hinzufügen, ohne wirklich so vielen Menschen zu helfen.
mgiuca
1
@mgiuca: Dinge zu haben, die bis auf Randfälle ziemlich ähnlich sind, ist oft äußerst nützlich, und fehlgeleitete Bemühungen, solche Dinge zu vermeiden, führen zu einer unnötigen Komplexität. Wenn für Client-Code manchmal Edge-Cases auf eine Weise und manchmal auf eine andere Weise behandelt werden müssen, wird durch eine Methode für jeden Handhabungsstil viel Edge-Case-Handling-Code im Client eliminiert. Was Ihre Analogie betrifft, gibt es keine Möglichkeit, die Operation mit Gleitkommawerten fester Größe zu definieren, um in allen Fällen transitive Ergebnisse zu erzielen (obwohl einige Sprachen der 1980er Jahre eine bessere Semantik hatten ...
Supercat
1
... als diesbezüglich heute) und daher sollte die Tatsache, dass sie nicht das Unmögliche tun, keine Überraschung sein. Es gibt jedoch kein grundlegendes Hindernis für die Implementierung einer Äquivalenzbeziehung, die universell auf jede Art von Wert anwendbar wäre, der kopiert werden kann.
Supercat
1

Gibt es dafür einen guten Grund? Warum sollte ein Vergleich von Mitglied zu Mitglied ein Problem sein?

Funktionell ist dies möglicherweise kein Problem, aber in Bezug auf die Leistung ist der Standardvergleich von Mitglied zu Mitglied möglicherweise nicht optimaler als die Standardzuweisung / das Kopieren von Mitglied zu Mitglied. Im Gegensatz zur Reihenfolge der Zuweisung wirkt sich die Reihenfolge des Vergleichs auf die Leistung aus, da das erste ungleiche Mitglied impliziert, dass der Rest übersprungen werden kann. Wenn es also einige Mitglieder gibt, die normalerweise gleich sind, möchten Sie sie zuletzt vergleichen, und der Compiler weiß nicht, welche Mitglieder mit größerer Wahrscheinlichkeit gleich sind.

Betrachten Sie dieses Beispiel, in dem verboseDescriptioneine lange Zeichenfolge aus einem relativ kleinen Satz möglicher Wetterbeschreibungen ausgewählt wird.

class LocalWeatherRecord {
    std::string verboseDescription;
    std::tm date;
    bool operator==(const LocalWeatherRecord& other){
        return date==other.date
            && verboseDescription==other.verboseDescription;
    // The above makes a lot more sense than
     // return verboseDescription==other.verboseDescription
     //     && date==other.date;
    // because some verboseDescriptions are liable to be same/similar
    }
}

(Natürlich wäre der Compiler berechtigt, die Reihenfolge der Vergleiche zu ignorieren, wenn er erkennt, dass sie keine Nebenwirkungen haben, aber vermutlich würde er seine Warteschlange immer noch aus dem Quellcode entnehmen, wo er selbst keine besseren Informationen hat.)

Museful
quelle
Aber niemand hält Sie davon ab, einen optimierten benutzerdefinierten Vergleich zu schreiben, wenn Sie ein Leistungsproblem finden. Nach meiner Erfahrung wäre dies jedoch eine winzige Minderheit der Fälle.
Peter - Reinstate Monica
1

Nur damit die Antworten auf diese Frage im Laufe der Zeit vollständig bleiben: Seit C ++ 20 kann sie automatisch mit Befehl generiert werden auto operator<=>(const foo&) const = default;

Es werden alle Operatoren generiert: == ,! =, <, <=,> Und> =, Einzelheiten finden Sie unter https://en.cppreference.com/w/cpp/language/default_comparisons .

Aufgrund des Aussehens des Bedieners <=>wird es als Raumschiffbetreiber bezeichnet. Siehe auch Warum benötigen wir den Raumschiffoperator <=> in C ++? .

BEARBEITEN: Auch in C ++ 11 ist ein ziemlich guter Ersatz dafür verfügbar. Ein vollständiges Codebeispiel mit finden std::tieSie unter https://en.cppreference.com/w/cpp/utility/tuple/tiebool operator<(…) . Der interessante Teil, mit dem gearbeitet wurde, ==ist:

#include <tuple>

struct S {
………
bool operator==(const S& rhs) const
    {
        // compares n to rhs.n,
        // then s to rhs.s,
        // then d to rhs.d
        return std::tie(n, s, d) == std::tie(rhs.n, rhs.s, rhs.d);
    }
};

std::tie funktioniert mit allen Vergleichsoperatoren und wird vom Compiler vollständig optimiert.

cosurgi
quelle
-1

Ich stimme zu, für POD-Typklassen könnte der Compiler dies für Sie tun. Was Sie jedoch für einfach halten, kann der Compiler falsch machen. Es ist also besser, den Programmierer das tun zu lassen.

Ich hatte einmal einen POD-Fall, in dem zwei der Felder eindeutig waren - ein Vergleich würde also niemals als wahr angesehen werden. Der Vergleich, den ich brauchte, wurde jedoch immer nur mit der Nutzlast verglichen - etwas, das der Compiler niemals verstehen würde oder jemals selbst herausfinden könnte.

Außerdem - das Schreiben dauert nicht lange, oder?!

graham.reeds
quelle