Dies ist der Code aus dem C ++ - Standardbibliothekscode remove
. Warum wird Ungleichheit als if (!(*first == val))
statt getestet if (*first != val)
?
template <class ForwardIterator, class T>
ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& val)
{
ForwardIterator result = first;
while (first!=last) {
if (!(*first == val)) {
*result = *first;
++result;
}
++first;
}
return result;
}
operator!=
. Verwenden Sie einfach dieoperator==
Implementierung:bool operator!=(const Foo& other) { return !(*this == other); }
operator==
erwartet wird, dass sie hier verwendet werden ...const
Beispiel in meinem vorherigen Kommentar geben, aber Sie verstehen es. (Zu spät, um es zu bearbeiten)EqualityComparable
das Hurkyl in seiner Antwort erwähnt hat .Antworten:
Weil dies bedeutet, dass die einzige Anforderung an T darin besteht, eine zu implementieren
operator==
. Sie könnten T benötigen, um eine zu haben,operator!=
aber die allgemeine Idee hier ist, dass Sie den Benutzer der Vorlage so wenig wie möglich belasten sollten und andere Vorlagen benötigenoperator==
.quelle
x != y
ist nicht definiert als!(x == y)
. Was ist, wenn diese Operatoren den Analysebaum eines eingebetteten DSL zurückgeben?!=
unterstützt wird (würde fälschlicherweise true zurückgeben - auch wenn diesoperator==
nicht unterstützt wird!). Ich mache mir auch Sorgen, dass dadurch einige Verwendungen von!=
mehrdeutig werden.Die meisten Funktionen in STL funktionieren nur mit
operator<
oderoperator==
. Dies erfordert, dass der Benutzer nur diese beiden Operatoren (oder manchmal mindestens einen von ihnen) implementiert. Zum Beispielstd::set
verwendetoperator<
(genauer gesagt,std::less
wasoperator<
standardmäßig aufgerufen wird) und nichtoperator>
, um die Bestellung zu verwalten. Dieremove
Vorlage in Ihrem Beispiel ist ein ähnlicher Fall - sie wird nur verwendetoperator==
und nicht,operator!=
sodass dieoperator!=
nicht definiert werden muss.quelle
operator<
direkt verwendet, sondern stattdessenstd::less
, was standardmäßig der Fall istoperator<
.std::set
tatsächlichoperator<
direkt verwendet werden. Seltsam ...std::equal_to
, sondernoperator==
wie in der Frage angegeben. Die Situation mitstd::less
ist ähnlich. Nun, vielleichtstd::set
ist nicht das beste Beispiel.std::equal_to
undstd::less
werden als Standardvorlagenparameter verwendet, wobei der Komparator als Parameter verwendet wird.operator==
undoperator<
werden direkt verwendet, wenn der Typ erforderlich ist, um eine vergleichbare Gleichheit bzw. eine strenge schwache Reihenfolge zu erfüllen, z. B. Iteratoren und Iteratoren mit wahlfreiem Zugriff.Falsch. Es ist nicht der C ++ - Standardbibliothekscode
remove
. Dies ist eine mögliche interne Implementierung der C ++ - Standardbibliotheksfunktionremove
. Der C ++ - Standard schreibt keinen tatsächlichen Code vor. Es schreibt Funktionsprototypen und erforderliche Verhaltensweisen vor.Mit anderen Worten: Aus strenger sprachlicher Sicht existiert der Code, den Sie sehen , nicht . Möglicherweise stammt es aus einer Header-Datei, die mit der Standardbibliotheksimplementierung Ihres Compilers geliefert wird. Beachten Sie, dass der C ++ - Standard nicht einmal erfordert, dass diese Header- Dateien vorhanden sind. Dateien sind nur eine bequeme Möglichkeit für Compiler-Implementierer, die Anforderungen für eine Zeile wie
#include <algorithm>
(dh das Bereitstellenstd::remove
und andere verfügbare Funktionen) zu erfüllen .Weil nur
operator==
von der Funktion benötigt wird.Wenn es um das Überladen von Operatoren für benutzerdefinierte Typen geht, können Sie mit der Sprache alle möglichen seltsamen Dinge tun. Sie können sehr gut eine Klasse erstellen, die überladen,
operator==
aber nicht überladen istoperator!=
. Oder noch schlimmer: Sie könnten überladen,operator!=
aber völlig unabhängige Dinge tun lassen.Betrachten Sie dieses Beispiel:
Bei
std::remove
Verwendungoperator!=
wäre das Ergebnis ganz anders.quelle
a==b
unda!=b
falsch zurückzugeben. Während es möglicherweise nicht immer klar ist, ob eine solche Situation sinnvoller als "gleich" oder "ungleich" angesehen wird, muss eine Funktion, die Gleichheit ausschließlich anhand des Operators "==" definiert, sie als "ungleich" betrachten ", unabhängig davon, welches Verhalten sinnvoller wäre [wenn ich meine Druthers hätte, würde von allen Typen erwartet, dass sich boolesche" == "- und"! = "- Operatoren konsistent verhalten, aber die Tatsache, dass IEEE-754 eine gebrochene Gleichheit vorschreibt Betreiber würden solche Erwartungen erschweren].==
und!=
verhält sich konsistent, obwohl ich immer gedacht habe, dass alle sechs Beziehungen ausgewertet werden sollten,false
wenn mindestens ein Operand vorhanden istNaN
.Einige gute Antworten hier. Ich wollte nur eine kleine Notiz hinzufügen.
Wie alle guten Bibliotheken basiert die Standardbibliothek auf (mindestens) zwei sehr wichtigen Prinzipien:
Übernehmen Sie den Benutzern Ihrer Bibliothek die geringste Verantwortung, mit der Sie durchkommen können. Ein Teil davon hat damit zu tun, dass sie bei der Verwendung Ihrer Benutzeroberfläche den geringsten Arbeitsaufwand haben. (wie das Definieren von so wenigen Operatoren, wie Sie durchkommen können). Der andere Teil hat damit zu tun, dass sie nicht überrascht werden oder dass sie Fehlercodes überprüfen müssen (also die Schnittstellen konsistent halten und Ausnahmen auslösen,
<stdexcept>
wenn etwas schief geht).Beseitigen Sie alle logischen Redundanzen . Alle Vergleiche können lediglich abgeleitet
operator<
werden. Warum also verlangen, dass Benutzer andere definieren? z.B:(a> b) ist äquivalent zu (b <a)
(a> = b) ist äquivalent zu! (a <b)
(a == b) ist äquivalent zu! ((a <b) || (b <a))
und so weiter.
In diesem Sinne könnte man sich natürlich fragen, warum dies
unordered_map
erforderlich istoperator==
(zumindest standardmäßig) und nichtoperator<
. Die Antwort ist, dass in einer Hash-Tabelle der einzige Vergleich, den wir jemals benötigen, ein Vergleich für die Gleichheit ist. Daher ist es logisch konsistenter (dh für den Bibliotheksbenutzer sinnvoller), von ihm die Definition eines Gleichheitsoperators zu verlangen. Das Erfordernis einesoperator<
wäre verwirrend, da nicht sofort klar ist, warum Sie es benötigen würden.quelle
operator==
(undhash
) erfordert .!(a==b)
. Da eine unreflektierte Überladung von Operatoren leicht dazu führen kann, dass das C ++ - Programm völlig durcheinander gerät (und der Programmierer verrückt wird, weil das Debuggen seines Codes zu einer unmöglichen Aufgabe werden kann, da das Auffinden des Täters eines bestimmten Fehlers einer Odyssee ähnelt).!((a < b) || (b < a))
verwendet einen Bool-Operator weniger, daher ist es wahrscheinlich schnellerDas
EqualityComparable
Konzept erfordert nur dieoperator==
Definition.Folglich kann sich jede Funktion, die behauptet, mit befriedigenden Typen zu arbeiten,
EqualityComparable
nicht auf die Existenz vonoperator!=
Objekten dieses Typs verlassen. (es sei denn, es gibt zusätzliche Anforderungen, die das Vorhandensein von implizierenoperator!=
).quelle
Von Boost FAQ: Quelle
Da Sie wissen, dass das Erfordernis der
==
Implementierung eine Belastung darstellt , möchten Sie niemals eine zusätzliche Belastung schaffen, indem Sie auch die!=
Implementierung erfordern .Für mich persönlich geht es um SOLID (objektorientiertes Design) L-Teil - Liskov-Substitutionsprinzip: „Objekte in einem Programm sollten durch Instanzen ihrer Subtypen ersetzt werden können, ohne die Richtigkeit dieses Programms zu ändern.“ In diesem Fall ist es der Operator ! = , Den ich in der booleschen Logik durch == und boolean inverse ersetzen kann .
quelle