Sind == und! = Voneinander abhängig?


292

Ich lerne über das Überladen von Operatoren in C ++, und ich sehe das ==und !=sind einfach einige spezielle Funktionen, die für benutzerdefinierte Typen angepasst werden können. Mein Anliegen ist jedoch, warum zwei separate Definitionen erforderlich sind. Ich dachte, wenn a == bes wahr ist, dann a != bist es automatisch falsch und umgekehrt, und es gibt keine andere Möglichkeit, weil es per Definition a != bist !(a == b). Und ich konnte mir keine Situation vorstellen, in der dies nicht stimmte. Aber vielleicht ist meine Vorstellungskraft begrenzt oder ich weiß nichts?

Ich weiß, dass ich eins in Bezug auf das andere definieren kann, aber das ist nicht das, worüber ich frage. Ich frage auch nicht nach der Unterscheidung zwischen dem Vergleichen von Objekten nach Wert oder Identität. Oder ob zwei Objekte gleichzeitig gleich und ungleich sein könnten (dies ist definitiv keine Option! Diese Dinge schließen sich gegenseitig aus). Was ich frage, ist Folgendes:

Gibt es eine Situation, in der es Sinn macht, Fragen zu stellen, ob zwei Objekte gleich sind, aber zu fragen, ob sie nicht gleich sind, macht keinen Sinn? (entweder aus Sicht des Benutzers oder aus Sicht des Implementierers)

Wenn es keine solche Möglichkeit gibt, warum in C ++ werden diese beiden Operatoren dann als zwei unterschiedliche Funktionen definiert?


13
Zwei Zeiger können beide null sein, müssen aber nicht unbedingt gleich sein.
Ali Caglayan

2
Ich bin mir nicht sicher, ob es hier Sinn macht, aber als ich dies las, dachte ich an Kurzschlussprobleme. Zum Beispiel könnte man definieren, dass 'undefined' != expressionimmer wahr (oder falsch oder undefiniert) ist, unabhängig davon, ob der Ausdruck ausgewertet werden kann. In diesem Fall a!=bwürde das korrekte Ergebnis gemäß Definition zurückgegeben, es !(a==b)würde jedoch fehlschlagen, wenn bes nicht ausgewertet werden kann. (Oder nehmen Sie sich viel Zeit, wenn die Bewertung bteuer ist).
Dennis Jaheruddin

2
Was ist mit null! = Null und null == null? Es kann beides sein ... also wenn a! = B, bedeutet das nicht immer a == b.
Zozo

4
Ein Beispiel aus Javascript(NaN != NaN) == true
chiliNUT

Antworten:


272

Sie möchten nicht, dass die Sprache automatisch neu geschrieben wird a != b, !(a == b)wenn a == betwas anderes als a zurückgegeben wird bool. Und es gibt einige Gründe, warum Sie das dazu bringen könnten.

Möglicherweise verfügen Sie über Expression Builder-Objekte, bei denen a == bkein Vergleich durchgeführt werden soll, sondern lediglich ein Ausdrucksknoten erstellt wird a == b.

Möglicherweise haben Sie eine verzögerte Auswertung, bei a == bder kein Vergleich direkt durchgeführt werden soll oder nicht, sondern eine Art zurückgegeben wird lazy<bool>, die zu booleinem späteren Zeitpunkt implizit oder explizit konvertiert werden kann, um den Vergleich tatsächlich durchzuführen. Möglicherweise mit den Expression Builder-Objekten kombiniert, um eine vollständige Ausdrucksoptimierung vor der Auswertung zu ermöglichen.

Möglicherweise haben Sie eine benutzerdefinierte optional<T>Vorlagenklasse, in der optionale Variablen angegeben sind tund die uSie zulassen möchten t == u, aber zurückgeben optional<bool>.

Es gibt wahrscheinlich mehr, an das ich nicht gedacht habe. Und obwohl in diesen Beispielen die Operation a == bund a != bbeides sinnvoll sind, ist dies immer noch a != bnicht dasselbe wie !(a == b), sodass separate Definitionen erforderlich sind.


72
Die Ausdrucksbildung ist ein fantastisches praktisches Beispiel dafür, wann Sie dies möchten, das nicht auf erfundenen Szenarien beruht.
Oliver Charlesworth

6
Ein weiteres gutes Beispiel wären vektorlogische Operationen. Sie würden eher ein Durchlauf durch die Daten der Berechnung !=Berechnung anstelle von zwei Durchgängen ==dann !. Besonders damals, als man sich nicht darauf verlassen konnte, dass der Compiler die Schleifen zusammenführt. Oder auch heute noch, wenn Sie den Compiler nicht überzeugen können, überlappen sich Ihre Vektoren nicht.

41
„Sie können Expression Builder - Objekte haben“ - und dann Operator !können auch einige Ausdruck Knoten bauen und wir sind immer noch in Ordnung zu ersetzen a != bmit !(a == b), so weit das geht. Gleiches gilt für lazy<bool>::operator!, es kann zurückkehren lazy<bool>. optional<bool>ist überzeugender, da die logische Wahrhaftigkeit von beispielsweise boost::optionaldavon abhängt, ob ein Wert existiert, nicht vom Wert selbst.
Steve Jessop

42
All das und Nans - bitte erinnere dich an das NaNs;
Jsbueno

9
@jsbueno: Es wurde weiter unten darauf hingewiesen, dass NaNs in dieser Hinsicht nichts Besonderes sind.
Oliver Charlesworth

110

Wenn es keine solche Möglichkeit gibt, warum in C ++ werden diese beiden Operatoren dann als zwei unterschiedliche Funktionen definiert?

Weil Sie sie überladen können und indem Sie sie überladen, können Sie ihnen eine völlig andere Bedeutung geben als ihre ursprüngliche.

Nehmen wir zum Beispiel den Operator <<, ursprünglich den bitweisen Linksverschiebungsoperator, der jetzt üblicherweise als Einfügeoperator überladen ist, wie in std::cout << something; völlig andere Bedeutung als das Original.

Wenn Sie also akzeptieren, dass sich die Bedeutung eines Operators ändert, wenn Sie ihn überladen, gibt es keinen Grund, den Benutzer daran zu hindern, dem Operator eine Bedeutung zu geben ==, die nicht genau die Negation des Operators ist !=, obwohl dies verwirrend sein kann.


18
Dies ist die einzige Antwort, die praktisch Sinn macht.
Sonic Atom

2
Mir scheint, Sie haben Ursache und Wirkung rückwärts. Sie können sie separat überlasten , da ==und !=existieren als verschiedene Operatoren. Auf der anderen Seite existieren sie wahrscheinlich nicht als separate Operatoren, da Sie sie separat überladen können, sondern aus Gründen des Legacy und der Bequemlichkeit (Code-Kürze).
Nitro2k01

60

Mein Anliegen ist jedoch, warum zwei separate Definitionen erforderlich sind.

Sie müssen nicht beide definieren.
Wenn sie sich gegenseitig ausschließen, können Sie dennoch präzise sein, indem Sie nur ==und <neben std :: rel_ops definieren

Aus Bezug:

#include <iostream>
#include <utility>

struct Foo {
    int n;
};

bool operator==(const Foo& lhs, const Foo& rhs)
{
    return lhs.n == rhs.n;
}

bool operator<(const Foo& lhs, const Foo& rhs)
{
    return lhs.n < rhs.n;
}

int main()
{
    Foo f1 = {1};
    Foo f2 = {2};
    using namespace std::rel_ops;

    //all work as you would expect
    std::cout << "not equal:     : " << (f1 != f2) << '\n';
    std::cout << "greater:       : " << (f1 > f2) << '\n';
    std::cout << "less equal:    : " << (f1 <= f2) << '\n';
    std::cout << "greater equal: : " << (f1 >= f2) << '\n';
}

Gibt es eine Situation, in der es Sinn macht, Fragen zu stellen, ob zwei Objekte gleich sind, aber zu fragen, ob sie nicht gleich sind?

Wir verbinden diese Operatoren häufig mit Gleichheit.
Obwohl sie sich bei grundlegenden Typen so verhalten, besteht keine Verpflichtung, dass dies ihr Verhalten bei benutzerdefinierten Datentypen ist. Sie müssen nicht einmal einen Bool zurückgeben, wenn Sie nicht möchten.

Ich habe gesehen, wie Leute Operatoren auf bizarre Weise überladen, nur um festzustellen, dass dies für ihre domänenspezifische Anwendung sinnvoll ist. Selbst wenn die Benutzeroberfläche zu zeigen scheint, dass sie sich gegenseitig ausschließen, möchte der Autor möglicherweise eine bestimmte interne Logik hinzufügen.

(entweder aus Sicht des Benutzers oder aus Sicht des Implementierers)

Ich weiß, dass Sie ein bestimmtes Beispiel möchten.
Hier ist eines aus dem Catch-Test-Framework , das ich für praktisch hielt:

template<typename RhsT>
ResultBuilder& operator == ( RhsT const& rhs ) {
    return captureExpression<Internal::IsEqualTo>( rhs );
}

template<typename RhsT>
ResultBuilder& operator != ( RhsT const& rhs ) {
    return captureExpression<Internal::IsNotEqualTo>( rhs );
}

Diese Operatoren machen verschiedene Dinge, und es wäre nicht sinnvoll, eine Methode als! (Nicht) der anderen zu definieren. Der Grund dafür ist, dass das Framework den durchgeführten Vergleich ausdrucken kann. Dazu muss der Kontext erfasst werden, in dem der überladene Operator verwendet wurde.


14
Oh mein Gott, wie konnte ich nichts davon wissen std::rel_ops? Vielen Dank, dass Sie darauf hingewiesen haben.
Daniel Jour

5
Fast wörtliche Kopien von cppreference (oder irgendwo anders) sollten klar gekennzeichnet und richtig zugeordnet sein. rel_opsist sowieso schrecklich.
TC

@TC Einverstanden, ich sage nur, es ist eine Methode, die OP annehmen kann. Ich kann rel_ops nicht einfacher erklären als das gezeigte Beispiel. Ich habe verlinkt, wo es ist, aber Code gepostet, da sich die Referenzseite immer ändern könnte.
Trevor Hickey

4
Sie müssen noch klarstellen, dass das Codebeispiel zu 99% von cppreference stammt und nicht von Ihrem eigenen.
TC

2
Std :: relops scheint in Ungnade gefallen zu sein. Schauen Sie sich Boost-Ops an, um etwas gezielteres zu finden.
JDługosz

43

Es gibt einige sehr gut etablierte Konventionen , in denen (a == b)und (a != b)sind beide falsch nicht unbedingt Gegensätze. Insbesondere in SQL ergibt jeder Vergleich mit NULL NULL, nicht wahr oder falsch.

Es ist wahrscheinlich keine gute Idee, wenn möglich neue Beispiele dafür zu erstellen, da dies so unintuitiv ist. Wenn Sie jedoch versuchen, eine vorhandene Konvention zu modellieren, ist es hilfreich, die Option zu haben, dass sich Ihre Operatoren dafür "korrekt" verhalten Kontext.


4
SQL-ähnliches Nullverhalten in C ++ implementieren? Ewwww. Aber ich nehme an, es ist nicht etwas, von dem ich denke, dass es in der Sprache verboten werden sollte, wie unangenehm es auch sein mag.

1
@ dan1111 Noch wichtiger ist, dass einige SQL-Varianten möglicherweise in C ++ codiert sind, sodass die Sprache ihre Syntax unterstützen muss, nicht wahr?
Joe

1
Korrigieren Sie mich, wenn ich falsch liege. Ich gehe hier nur von Wikipedia aus, aber ein Vergleich mit einem NULL-Wert in SQL gibt Unbekannt zurück, nicht Falsch? Und ist die Negation von Unbekannt nicht immer noch Unbekannt? Wenn also die SQL-Logik in C ++ codiert wäre, möchten Sie nicht NULL == somethingUnbekannt zurückgeben, und Sie möchten auch NULL != somethingUnbekannt zurückgeben, und Sie möchten !Unknownzurückkehren Unknown. Und in diesem Fall ist die Implementierung operator!=als Negation von operator==immer noch korrekt.
Benjamin Lindley

1
@Barmar: Okay, aber wie macht das dann die Aussage "SQL NULLs funktionieren so" richtig? Wenn wir unsere Implementierungen von Vergleichsoperatoren auf die Rückgabe von Booleschen Werten beschränken, bedeutet dies nicht einfach, dass die Implementierung von SQL-Logik mit diesen Operatoren unmöglich ist?
Benjamin Lindley

2
@Barmar: Nun nein, das ist nicht der Punkt. Das OP kennt diese Tatsache bereits, sonst würde diese Frage nicht existieren. Es ging darum, ein Beispiel vorzustellen, in dem es sinnvoll war, entweder 1) das eine operator==oder operator!=das andere zu implementieren , aber nicht das andere, oder 2) es operator!=auf eine andere Weise als die Negation von zu implementieren operator==. Und die Implementierung von SQL-Logik für NULL-Werte ist kein Fall.
Benjamin Lindley

23

Ich werde nur den zweiten Teil Ihrer Frage beantworten, nämlich:

Wenn es keine solche Möglichkeit gibt, warum in C ++ werden diese beiden Operatoren dann als zwei unterschiedliche Funktionen definiert?

Ein Grund, warum es sinnvoll ist, dem Entwickler zu erlauben, beide zu überlasten, ist die Leistung. Sie können Optimierungen zulassen, indem Sie sowohl ==als auch implementieren !=. Dann x != ykönnte billiger sein als!(x == y) ist. Einige Compiler können es möglicherweise für Sie optimieren, aber möglicherweise nicht, insbesondere wenn Sie komplexe Objekte mit viel Verzweigung haben.

Selbst in Haskell, wo Entwickler Gesetze und mathematische Konzepte sehr ernst nehmen, darf man beide überladen, ==und /=wie Sie hier sehen können ( http://hackage.haskell.org/package/base-4.9.0.0/docs/Prelude) .html # v: -61--61- ):

$ ghci
GHCi, version 7.10.2: http://www.haskell.org/ghc/  :? for help
λ> :i Eq
class Eq a where
  (==) :: a -> a -> Bool
  (/=) :: a -> a -> Bool
        -- Defined in `GHC.Classes'

Dies würde wahrscheinlich als Mikrooptimierung angesehen, könnte jedoch in einigen Fällen gerechtfertigt sein.


3
SSE-Wrapper-Klassen (x86 SIMD) sind ein gutes Beispiel dafür. Es gibt eine pcmpeqbAnweisung, aber keine gepackte Vergleichsanweisung, die eine! = Maske erzeugt. Wenn Sie also nicht einfach die Logik der Ergebnisse umkehren können, müssen Sie eine andere Anweisung verwenden, um sie zu invertieren. (Unterhaltsame Tatsache: AMDs XOP-Befehlssatz hat gepackte Vergleiche für neq. Schade, dass Intel XOP nicht übernommen / erweitert hat; es gibt einige nützliche Anweisungen in dieser bald toten ISA-Erweiterung.)
Peter Cordes

1
Der springende Punkt bei SIMD ist in erster Linie die Leistung, und Sie verwenden es normalerweise nur manuell in Schleifen, die für die Gesamtleistung wichtig sind. Das Speichern einer einzelnen Anweisung ( PXORmit allen Anweisungen zum Invertieren des Vergleichsmaskenergebnisses) in einer engen Schleife kann von Bedeutung sein.
Peter Cordes

Leistung als Grund ist nicht glaubwürdig, wenn der Overhead eine logische Negation ist .
Prost und hth. - Alf

Es kann mehr als eine logische Negation sein, wenn die Rechenkosten x == ywesentlich höher sind als x != y. Letzteres zu
berechnen

16

Gibt es eine Situation, in der es Sinn macht, Fragen zu stellen, ob zwei Objekte gleich sind, aber zu fragen, ob sie nicht gleich sind? (entweder aus Sicht des Benutzers oder aus Sicht des Implementierers)

Das ist eine Meinung. Vielleicht nicht. Da die Sprachdesigner jedoch nicht allwissend waren, beschlossen sie, Menschen, die möglicherweise auf Situationen stoßen, in denen dies (zumindest für sie) sinnvoll sein könnte, nicht einzuschränken.


13

Als Antwort auf die Bearbeitung;

Das heißt, wenn es für einen Typ möglich ist, den Operator zu haben, ==aber nicht den !=oder umgekehrt, und wann ist dies sinnvoll?

Im Allgemeinen macht es keinen Sinn. Gleichheits- und Vergleichsoperatoren kommen im Allgemeinen in Mengen vor. Wenn es die Gleichheit gibt, dann auch die Ungleichheit; kleiner als, dann größer als und so weiter mit dem <=usw. Ein ähnlicher Ansatz wird auch auf die arithmetischen Operatoren angewendet, sie kommen im Allgemeinen auch in natürlichen logischen Mengen vor.

Dies zeigt sich in der std::rel_ops Namespace belegt. Wenn Sie die Gleichheit und weniger als Operatoren implementieren, erhalten Sie bei Verwendung dieses Namespace die anderen, die in Bezug auf Ihre ursprünglich implementierten Operatoren implementiert wurden.

Gibt es Bedingungen oder Situationen, in denen das eine nicht unmittelbar das andere bedeuten würde oder nicht in Bezug auf die anderen umgesetzt werden könnte? Ja, es gibt wohl nur wenige, aber sie sind da; wieder, wie sich im rel_opsSein eines eigenen Namespace zeigt. Aus diesem Grund können Sie durch die unabhängige Implementierung der Sprache die Sprache nutzen, um die gewünschte oder benötigte Semantik auf eine Weise zu erhalten, die für den Benutzer oder Client des Codes immer noch natürlich und intuitiv ist.

Die bereits erwähnte träge Bewertung ist ein hervorragendes Beispiel dafür. Ein weiteres gutes Beispiel ist die Semantik, die überhaupt keine Gleichheit oder Ungleichheit bedeutet. Ein ähnliches Beispiel dafür ist die Bitverschiebung Betreiber <<und >>für den Strom Einführen und Herausziehen verwendet wird. Obwohl es in allgemeinen Kreisen verpönt sein mag, kann es in einigen domänenspezifischen Bereichen sinnvoll sein.


12

Wenn die Operatoren ==und !=tatsächlich keine Gleichheit implizieren, genauso wie die <<und>> Operatoren stream keine Bitverschiebung. Wenn Sie die Symbole so behandeln, als ob sie ein anderes Konzept bedeuten, müssen sie sich nicht gegenseitig ausschließen.

In Bezug auf die Gleichheit kann es sinnvoll sein, wenn Ihr Anwendungsfall die Behandlung von Objekten als nicht vergleichbar rechtfertigt, sodass jeder Vergleich false zurückgeben sollte (oder einen nicht vergleichbaren Ergebnistyp, wenn Ihre Operatoren non-bool zurückgeben). Ich kann mir keine bestimmte Situation vorstellen, in der dies gerechtfertigt wäre, aber ich könnte sehen, dass dies vernünftig genug ist.


7

Mit großer Kraft kommt verantwortungsbewusst oder zumindest wirklich gute Styleguides.

==und !=kann überladen werden, um zu tun, was zum Teufel Sie wollen. Es ist sowohl ein Segen als auch ein Fluch. Es gibt keine Garantie , dass !=Mittel !(a==b).


6
enum BoolPlus {
    kFalse = 0,
    kTrue = 1,
    kFileNotFound = -1
}

BoolPlus operator==(File& other);
BoolPlus operator!=(File& other);

Ich kann diese Überladung des Operators nicht rechtfertigen, aber im obigen Beispiel ist es unmöglich, operator!=das "Gegenteil" von zu definieren operator==.



1
@Snowman: Dafang sagt nicht, dass es eine gute Aufzählung ist (noch eine gute Idee, eine solche Aufzählung zu definieren), es ist nur ein Beispiel, um einen Punkt zu veranschaulichen. Mit dieser (vielleicht schlechten) Operatordefinition !=würde dann ja nicht das Gegenteil von bedeuten ==.
AlainD

1
@AlainD Haben Sie auf den von mir geposteten Link geklickt und sind Sie sich des Zwecks dieser Website bewusst? Dies nennt man "Humor".

1
@Snowman: Das tue ich auf jeden Fall ... Entschuldigung, ich habe verpasst, dass es ein Link war und als Ironie gedacht war! : o)
AlainD

Warten Sie, Sie überladen unary ==?
LF

5

Am Ende überprüfen Sie mit diesen Operatoren, ob der Ausdruck a == boder a != bein boolescher Wert ( trueoder false) zurückgegeben wird. Dieser Ausdruck gibt nach dem Vergleich einen Booleschen Wert zurück, anstatt sich gegenseitig auszuschließen.


4

[..] Warum werden zwei separate Definitionen benötigt?

Eine zu berücksichtigende Sache ist, dass es die Möglichkeit gibt, einen dieser Operatoren effizienter zu implementieren, als nur die Negation des anderen zu verwenden.

(Mein Beispiel hier war Müll, aber der Punkt bleibt bestehen. Denken Sie an Bloom-Filter, zum Beispiel: Sie ermöglichen schnelle Tests, wenn etwas nicht in einem Set enthalten ist, aber das Testen, ob es vorhanden ist, kann viel länger dauern.)

[..] per Definition a != bist !(a == b).

Und es liegt in Ihrer Verantwortung als Programmierer, dies zu gewährleisten. Wahrscheinlich eine gute Sache, um einen Test zu schreiben.


4
Wie erlaubt man !((a == rhs.a) && (b == rhs.b))keinen Kurzschluss? Wenn !(a == rhs.a), dann (b == rhs.b)wird nicht ausgewertet.
Benjamin Lindley

Dies ist jedoch ein schlechtes Beispiel. Der Kurzschluss bringt hier keinen magischen Vorteil.
Oliver Charlesworth

@Oliver Charlesworth Alleine nicht, aber wenn es mit separaten Operatoren verbunden ist, funktioniert es: In diesem Fall ==wird der Vergleich beendet, sobald die ersten entsprechenden Elemente ungleich sind. Aber im Falle der !=, wenn er in Bezug auf die durchgeführt wurden ==, wäre es müssen zuerst alle die entsprechenden Elemente vergleichen (wenn sie alle gleich sind) in der Lage sein zu sagen , dass sie nicht nicht-gleich: P Aber wenn sie umgesetzt werden, wie in Im obigen Beispiel wird der Vergleich beendet, sobald das erste ungleiche Paar gefunden wird. Ein großartiges Beispiel.
BarbaraKwarc

@BenjaminLindley Stimmt, mein Beispiel war völliger Unsinn. Leider kann ich mir keinen anderen Geldautomaten einfallen lassen, hier ist es zu spät.
Daniel Jour

1
@BarbaraKwarc: !((a == b) && (c == d))und (a != b) || (c != d)sind in Bezug auf die Kurzschlusseffizienz gleichwertig.
Oliver Charlesworth

2

Durch Anpassen des Verhaltens der Operatoren können Sie sie dazu bringen, das zu tun, was Sie wollen.

Möglicherweise möchten Sie die Dinge anpassen. Beispielsweise möchten Sie möglicherweise eine Klasse anpassen. Objekte dieser Klasse können nur durch Überprüfen einer bestimmten Eigenschaft verglichen werden. Wenn Sie wissen, dass dies der Fall ist, können Sie einen bestimmten Code schreiben, der nur die minimalen Dinge überprüft, anstatt jedes einzelne Bit jeder einzelnen Eigenschaft im gesamten Objekt zu überprüfen.

Stellen Sie sich einen Fall vor, in dem Sie herausfinden können, dass etwas genauso schnell, wenn nicht sogar schneller anders ist, als Sie herausfinden können, dass etwas dasselbe ist. Zugegeben, sobald Sie herausgefunden haben, ob etwas gleich oder verschieden ist, können Sie das Gegenteil erkennen, indem Sie einfach ein wenig umdrehen. Das Umdrehen dieses Bits ist jedoch eine zusätzliche Operation. In einigen Fällen kann das Speichern einer Operation (multipliziert mit einem Vielfachen) zu einer Erhöhung der Gesamtgeschwindigkeit führen, wenn der Code häufig erneut ausgeführt wird. (Wenn Sie beispielsweise einen Vorgang pro Pixel eines Megapixel-Bildschirms speichern, haben Sie gerade eine Million Vorgänge gespeichert. Multipliziert mit 60 Bildschirmen pro Sekunde und Sie speichern noch mehr Vorgänge.)

Die Antwort von hvd enthält einige zusätzliche Beispiele.


2

Ja, weil einer "gleichwertig" und ein anderer "nicht gleichwertig" bedeutet und sich diese Begriffe gegenseitig ausschließen. Jede andere Bedeutung für diesen Operator ist verwirrend und sollte auf jeden Fall vermieden werden.


Sie schließen sich nicht in allen Fällen gegenseitig aus . Zum Beispiel zwei Unendlichkeiten, die beide nicht gleich und nicht gleich sind.
Vladon

@vladon kann im generischen Fall eine anstelle der anderen verwenden ? Nein, das heißt, sie sind einfach nicht gleich. Der Rest geht an eine spezielle Funktion und nicht an den Operator == /! =
oliora

@vladon bitte, anstatt generischen Fall alle Fälle in meiner Antwort zu lesen .
Oliora

@vladon So sehr dies in der Mathematik zutrifft, können Sie ein Beispiel geben, bei dem C aus diesem Grund a != bnicht gleich ist !(a == b)?
Nitro2k01

2

Vielleicht eine unvergleichbar Regel wo a != bwar falsch und a == bwar falsch wie ein stateless Bit.

if( !(a == b || a != b) ){
    // Stateless
}

Wenn Sie logische Symbole neu anordnen möchten, wird! ([A] || [B]) logisch zu ([! A] & [! B])
Thijser

Beachten Sie, dass der Rückgabetyp von operator==()und operator!=()nicht unbedingt bool, sie können eine Aufzählung sein, die zustandslos enthält, wenn Sie das wollten, und dennoch können die Operatoren so definiert werden, dass sie gelten (a != b) == !(a==b).
Lorro
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.