Gibt es tatsächlich einen Grund, warum überladen & amp; & amp; und || nicht kurzschließen?
Den Kurzschluss Verhalten der Betreiber &&
und ||
ist ein wunderbares Werkzeug für Programmierer.
Aber warum tun, verlieren Sie dieses Verhalten, wenn Sie überlastet? Ich verstehe, dass die Betreiber lediglich syntaktischer Zucker für Funktionen, sondern Operatoren, für bool
haben dieses Verhalten, warum sollte es beschränkt sein auf diese Art? Gibt es irgendwelche technischen Gründe, die hinter dieser?
InformationsquelleAutor der Frage iFreilicht | 2014-09-18
Du musst angemeldet sein, um einen Kommentar abzugeben.
Alle design-Prozesse führen, Kompromisse zwischen unvereinbare Ziele. Leider gestaltet sich der Prozess für die überladene
&&
- operator in C++ erzeugt einen verwirrenden Ergebnis, dass die sehr Funktion, die Sie möchten, aus&&
- Kurzschluss Verhalten-ist weggelassen.Details wie die design-Prozess endete in dieser unglücklichen Stelle, die ich nicht kenne. Es ist jedoch relevant, um zu sehen, wie ein später-design-Prozess nahm diese unangenehme Ergebnis berücksichtigt. In C#, die überlastet
&&
Betreiber ist kurzschließen. Wie haben die Designer von C# erreichen?Einer der anderen Antworten schlägt vor, dass "lambda-lifting". Das heißt:
realisiert werden konnte, als etwas moralisch äquivalent zu:
wobei das zweite argument verwendet einen Mechanismus für lazy evaluation, so dass, wenn ausgewertet, die Nebenwirkungen und mit dem Wert des Ausdrucks hergestellt werden. Die Umsetzung der überladene operator würde nur die lazy evaluation, wenn nötig.
Dies ist nicht das, was die C# - design-team hat. (Beiseite: wenn die lambda-lifting istwas ich Tat wenn die Zeit gekommen war, zu tun Ausdruck-Darstellung der
??
Betreiber, die verlangt, dass bestimmte umwandlungsvorgänge durchgeführt werden träge. Beschreiben im detail, würde aber ein wichtiger Exkurs. Es genügt zu sagen: lambda-lifting funktioniert, ist aber ausreichend Schwergewicht, dass wir wünschte, es zu vermeiden.)Eher der C# - Lösung, die Pausen, das problem in zwei getrennte Probleme:
Daher ist das problem gelöst, indem es illegale überlastung
&&
direkt. Eher in C# überladen müssen zwei Operatoren, von denen jeder beantwortet eine dieser beiden Fragen.(Beiseite: eigentlich drei. C# erfordert, dass, wenn der Betreiber
false
vorgesehen ist dann Betreibertrue
müssen auch zur Verfügung gestellt werden, welche Antworten auf die Frage: ist diese Sache, die "true" -ish?". In der Regel gibt es keinen Grund zu liefern, nur einen solchen operator, so C# benötigt.)Betrachten eine Aussage der form:
Generiert der compiler code für diese Gedanken, den Sie geschrieben hatte, dieses pseudo-C#:
Wie Sie sehen können auf der linken Seite wird immer ausgewertet. Wenn es bestimmt wird, "false" -isch", dann ist das das Ergebnis. Andernfalls, wird die Rechte Seite ausgewertet wird, und die eifrig user-defined-operator
&
aufgerufen.Den
||
operator definiert ist, in der analogen Weise, wie ein Aufruf von operator true und die eifrigen|
Betreiber:Durch die Definition aller vier Operatoren --
true
false
&
und|
-- C# können Sie nicht nur sagencleft && cright
aber auch non-short-circuitingcleft & cright
und auchif (cleft) if (cright) ...
undc ? consequence : alternative
undwhile(c)
und so weiter.Nun, ich sagte, dass alle design-Prozesse sind das Ergebnis von Kompromissen. Hier der C# - Sprache, die Designer geschafft, den Kurzschluss
&&
und||
Recht, aber dies erfordert eine überlastung vier Operatoren statt zweidie finden manche Leute Sie verwirrend. Der operator true/false-Funktion ist eine der am wenigsten bekannten features in C#. Das Ziel, eine sinnvolle und einfache Sprache, die vertraut ist, um C++ - Benutzer war entgegen der Wünsche zu kurzschließen und den Wunsch nicht umsetzen lambda-lifting oder andere Formen der lazy evaluation. Ich glaube, das war ein vernünftiger Kompromiss, aber es ist wichtig zu erkennen, dass es ist einen Kompromiss. Nur ein verschiedenen Kompromiss, als die Designer von C++ gelandet.Wenn das Thema der design-Sprache für solche Operatoren, die Sie interessiert, betrachten, Lesen, meine Serien auf, warum C# nicht definieren diese Operatoren auf nullable Boolean:
http://ericlippert.com/2012/03/26/null-is-not-false-part-one/
InformationsquelleAutor der Antwort Eric Lippert
Der Punkt ist, dass (in den Grenzen von C++98) den rechten Operanden weitergegeben werden, der überladene operator-Funktion als argument. Dabei es wäre schon ausgewertet. Es gibt nichts, das
operator||()
oderoperator&&()
code konnte oder nicht tun konnte, würde dies vermeiden.Den ursprünglichen Betreiber ist anders, weil es nicht eine Funktion, sondern realisiert sich auf einer niedrigeren Ebene der Sprache.
Zusätzliche Funktionen der Sprache könnte gemacht haben, nicht-Bewertung des rechten Operanden syntaktisch möglich. Sie haben jedoch nicht die Mühe, weil es gibt nur wenige Fälle, in denen dieses wäre semantisch nützlich. (Genau wie
? :
die nicht zur Verfügung für das überladen überhaupt.(Es dauerte 16 Jahre, um lambdas in der standard...)
Als für die semantische berücksichtigen:
Dies hinausläuft:
Überlegen Sie, was genau Sie tun möchten mit objectB (unbekannter Typ), andere als der Aufruf einen Konvertierungs-operator zur
bool
und wie würden Sie setzen, dass in Wörter für die Sprache, die definition.Und wenn Sie sind Aufruf Konvertierung zu bool, gut...
tut die gleiche Sache, jetzt tut es? Warum also überlastung in den ersten Platz?
InformationsquelleAutor der Antwort DevSolar
Einem feature gedacht, entworfen, implementiert, dokumentiert und versendet.
Nun dachten wir, lasst uns sehen, warum es möglicherweise einfach jetzt (und schwer). Beachten Sie auch, dass es nur eine begrenzte Menge von Ressourcen, so dass das hinzufügen möglicherweise gehackt etwas anderes (Was würden Sie gerne verzichten?).
In der Theorie, alle Operatoren ermöglichen könnte, Kurzschluss Verhalten mit nur einem "kleinen" zusätzliche Sprache-Funktionals von C++11 (wenn Lambda-Ausdrücke eingeführt wurden, 32 Jahre nach "C mit Klassen" begannen im Jahr 1979, eine immer noch respektable 16 nach c++98):
C++ würde nur einen Weg brauchen, um kommentieren ein argument als faul bewertet - ein hidden-lambda - zu vermeiden, die evaluation bis notwendig und zulässig (Voraussetzungen erfüllt).
Was wäre das theoretische Funktion Aussehen (denken Sie Daran, dass alle neuen Funktionen umfassend nutzbar)?
Einer annotation
lazy
die angewendet auf eine Funktion-argument der Funktion eine Vorlage erwartet einen Funktor, und lässt den compiler pack den Ausdruck in einen Funktor:Würde es Aussehen, unter der Haube wie:
Ganz besonders zu beachten, dass die lambda verborgen bleibt, und wird aufgerufen, bei den meisten einmal.
Es sollte keine performance-Verschlechterung aufgrund dieser, abgesehen von der reduzierten Chancen, common-subexpression-elimination.
Neben der Implementierung Komplexität und konzeptionelle Komplexität (jede Funktion erhöht die beiden, es sei denn, es ausreichend vereinfacht diese Komplexität für einige andere Funktionen), schauen wir uns eine weitere wichtige überlegung: Rückwärts-Kompatibilität.
Während dieser Sprache-Funktion nicht brechen würde jeder code, es würde subtil ändern API nutzen, was bedeutet, dass jede Nutzung in vorhandenen Bibliotheken wäre eine Stille brechen ändern.
BTW: Diese Funktion, während die einfacher zu verwenden, ist streng stärker als die C# - Lösung der Aufteilung
&&
und||
in zwei Funktionen, die jeweils für die getrennte definition.InformationsquelleAutor der Antwort Deduplicator
Mit retrospektiven Rationalisierung, vor allem, weil
damit gewährleistet Kurzschluss (ohne Einführung neuer syntax) die Betreiber müssten eingeschränkt werden, um
Ergebnisseerste argument Cabrio zubool
undkurzschließen kann einfach ausgedrückt auch in anderer Weise, wenn Sie benötigt wird.
Zum Beispiel, wenn eine Klasse
T
verbunden&&
und||
Operatoren, dann ist der Ausdruckwo
a
b
undc
sind Ausdrücke der FormT
ausgedrückt werden können mit Kurzschluss alsoder vielleicht deutlicher als
Die scheinbare Redundanz erhält alle Nebenwirkungen, die aus dem operator aufrufen.
Während die lambda-rewrite ist Ausführlicher, besser die Kapselung erlaubt es, die definieren solche Operatoren.
Ich bin mir nicht ganz sicher, ob der standard-Konformität in allen der folgenden (noch ein bisschen influensa), aber es kompiliert sauber mit Visual C++ 12.0 (2013) und MinGW g++ 4.8.2:
Ausgabe:
Hier jeder
!!
bang-bang zeigt, dass die Umstellung aufbool
d.h. argument-Wert-Prüfung.Da ein compiler kann leicht das gleiche tun, und zusätzlich zu optimieren, ist dies eine gezeigt, möglich, die Umsetzung und den Anspruch der Unmöglichkeit sein muss, setzen Sie in die gleiche Kategorie wie die Unmöglichkeit behauptet im Allgemeinen, nämlich in der Regel Mist.
InformationsquelleAutor der Antwort Cheers and hth. - Alf
tl;dr: es ist nicht der Mühe Wert, aufgrund der sehr geringen Nachfrage (wer würde das feature?) im Vergleich zu eher hohen Kosten (spezielle syntax erforderlich).
Das erste, was mir einfällt, ist, dass operator-überladung ist nur eine Phantasie Art zu schreiben von Funktionen, in der Erwägung, dass der boolean-version der Operatoren
||
und&&
sind buitlin Zeug. Das bedeutet, dass der compiler hat die Freiheit zu kurzschließen, während der Ausdruckx = y && z
mit nonbooleany
undz
führen muss, um einen Aufruf einer Funktion, wieX operator&& (Y, Z)
. Dies würde bedeuten, dassy && z
ist nur eine Phantasie Art zu schreibenoperator&&(y,z)
ist nur einen Anruf von einer seltsam benannten Funktion, wo beide Parameter ausgewertet werden müssen, bevor Sie die Funktion aufrufen (darunter alles, was würden Sie erachten einen Kurzschluss geeignet).Allerdings könnte man argumentieren, dass es möglich sein sollte, um die übersetzung von
&&
Betreiber etwas anspruchsvollere, wie es für dienew
Betreiber, die übersetzt wird in den Aufruf der Funktionoperator new
gefolgt von einem Konstruktor-Aufruf.Technisch wäre dies kein problem wäre zu definieren, eine Sprache-spezifische syntax für die Voraussetzung, die es ermöglicht, Kurzschluss. Aber auch der Einsatz von Kurzschlüssen wäre auf Fälle beschränkt werden, wo
Y
ist convetible zuX
oder aber es musste sein, zusätzliche info, wie man tatsächlich tun, um Kurzschlüsse (d.h. berechnen Sie das Ergebnis von der nur der erste parameter). Das Ergebnis müsste ähnlich Aussehen, wie diese:Einer selten will überlast
operator||
undoperator&&
weil es selten ist ist ein Fall, wo das schreibena && b
tatsächlich ist intuitive in nonboolean Kontext. Die einzigen Ausnahmen die ich kenne sind expression-templates, z.B. für eingebettete DSLs. Und nur eine Handvoll von diesen wenigen Fällen würde davon profitieren, Kurzschluss-Auswertung. Expression templates in der Regel nicht, weil Sie verwendet werden, um form Ausdruck Bäume, die später ausgewertet, so muss man immer beide Seiten des Ausdrucks.Kurz gesagt: weder die compiler-Autoren noch standards Autoren das Bedürfnis verspürt, durch Reifen springen und definieren und implementieren zusätzliche umständliche syntax, nur weil einer in einer million, könnte auf die Idee kommen, dass es schön wäre zu haben Kurzschluss auf Benutzer definiert
operator&&
undoperator||
- nur um zu dem Schluss, dass es ist nicht weniger Aufwand als das schreiben der logic pro hand.InformationsquelleAutor der Antwort Arne Mertz
Kurzschließen der logischen Operatoren ist erlaubt, denn es ist eine "Optimierung" bei der Bewertung der damit verbundenen Wahrheit Tabellen. Es ist ein Funktion der Logik selbst, und diese Logik definiert ist.
Benutzerdefinierten überladenen logischen Operatoren sind nicht verpflichtet Folgen der Logik der Wahrheit Tabellen.
Daher die gesamte Funktion, die ausgewertet werden müssen wie normal. Der compiler muss es behandeln wie eine normale überladene operator (oder Funktion) und kann es immer noch anwenden, Optimierungen, wie wäre es mit einer anderen Funktion.
Menschen überlasten Sie die logischen Operatoren, die für eine Vielzahl von Gründen. Zum Beispiel; Sie können spezifische Bedeutung in einem spezifischen Bereich, der nicht der "normalen" logische Menschen sind daran gewöhnt,.
InformationsquelleAutor der Antwort Niall
Den Kurzschluss ist, weil der Wahrheitstabelle von "und" und "oder". Wie würden Sie wissen, welche operation der Benutzer definieren und wie würden Sie wissen, dass Sie nicht haben, um zu evaluieren, der zweite operator?
InformationsquelleAutor der Antwort nj-ath
Lambdas ist nicht die einzige Möglichkeit zur Einführung von Faulheit. Lazy evaluation ist relativ straight-forward mit Expression Templates in C++. Es gibt keine Notwendigkeit, für die keyword -
lazy
und es umgesetzt werden kann in C++98. Ausdruck Bäume sind schon oben erwähnt. Expression templates sind schlecht (aber clever) Mannes Ausdruck Bäume. Der trick ist, konvertiert den Ausdruck in einen Baum, der rekursiv verschachtelten Instanzen desExpr
Vorlage. Der Baum wird getrennt ausgewertet nach dem Bau.Der folgende code implementiert kurzgeschlossen
&&
und||
Operatoren für KlasseS
solangelogical_and
undlogical_or
Kostenlose Funktionen und es ist Cabrio zubool
. Der code ist in C++14, aber die Idee ist für C++98 auch. Sehen live-Beispiel.InformationsquelleAutor der Antwort Sumant
Ich will nur diese eine Antwort-Teil. Der Grund dafür ist, dass der eingebaute
&&
und||
Ausdrücke sind nicht implementiert, mit Funktionen überladen von Operatoren sind.Dass die Kurzschluss-Logik eingebaut, um den compiler zu verstehen, bestimmte Ausdrücke einfach. Es ist genau wie jede andere integrierte Ablaufsteuerung.
Doch operator overloading implementiert, mit Funktionen statt, die bestimmten Regeln, und eine davon ist, dass alle Ausdrücke, die als Argumente bekommen ausgewertet, bevor die Funktion aufgerufen wird. Offensichtlich andere Regeln definiert werden könnte, aber das ist eine größere Aufgabe.
InformationsquelleAutor der Antwort bames53