Warum ist es nicht möglich, den ternären Operator zu überladen?

Lesezeit: 7 Minuten

Warum ist es nicht moglich den ternaren Operator zu uberladen
Paul Renton

Warum kann der ternäre Operator ‘ ?: ‘ nicht überladen werden?

Ich verwende den ternären Operator oft, um if-Anweisungen zu konsolidieren, und bin neugierig, warum die Sprachdesigner entschieden haben, dass dieser Operator nicht überladen wird. Ich habe nach einer Erklärung dafür gesucht, warum in C++-Operatorüberladung, aber keine gefunden, die beschreibt, warum dies nicht möglich ist. Die Fußnote gibt lediglich Auskunft, dass sie nicht überladen werden darf.

Meine erste Vermutung ist, dass das Überladen des Operators fast immer die Nummer eins oder zwei der im obigen Link angegebenen Prinzipien verletzt. Die Bedeutung der Überladung wird selten offensichtlich oder klar sein oder sie weicht von ihrer ursprünglich bekannten Semantik ab.

Meine Frage ist also eher, warum dies nicht möglich ist, als wie, da ich weiß, dass dies nicht möglich ist.

  • Reicht es nicht aus, alles zu überladen, was innerhalb eines ternären Operators als “auswertend” ausgelegt werden könnte?

    – WhozCraig

    30. Juli ’13 um 17:26

  • mögliches Duplikat von Wie kann man den Bedingungsoperator überladen?

    – Wolke

    30. Juli ’13 um 17:27

  • Was genau würden Sie gerne überladen? Es ist ein if-else Aussage, wie können Sie sie sinnvoll ändern?

    – Mats Petersson

    30. Juli ’13 um 17:27

  • Danke für die Kommentare und den Link. Ich habe die verlinkte Frage als potenzielles Duplikat gesehen, aber dort keine Antworten gefunden, die meine Frage beantwortet haben.

    – Paul Renton

    30. Juli ’13 um 17:30


Wenn Sie den ternären Operator überschreiben könnten, müssten Sie Folgendes schreiben:

xxx operator ?: ( bool condition, xxx trueVal, xxx falseVal );

Um Ihre Überschreibung aufzurufen, müsste der Compiler den Wert von beiden berechnen trueVal und falseVal. So funktioniert der eingebaute ternäre Operator nicht – er berechnet nur einen dieser Werte, weshalb Sie Dinge schreiben können wie:

return p == NULL ? 23 : p->value;

ohne sich Gedanken über die Umleitung über einen NULL-Zeiger machen zu müssen.

  • Die gleiche Argumentation gilt für && und ||, welche du kann Überlast.

    – James Kanze

    30. Juli ’13 um 17:30

  • @JamesKanze und was für eine schreckliche Entscheidung das war.

    – Nik Bougalis

    30. Juli ’13 um 17:35

  • @JamesKanze Natürlich. Rückblick ist etwas Wunderbares. Mir persönlich hätte es gefallen, wenn C++11 das Überladen von Operatoren deaktiviert hätte &&, || und , standardmäßig, es sei denn der Programmierer hat einen speziellen Header eingefügt (oder einen speziellen Compiler-Schalter übergeben). Ich glaube nicht, dass es für eine Sprache vernünftig ist, zuzulassen, dass sich vergangene Fehler ständig auf dem Altar der Abwärtskompatibilität ausbreiten.

    – Nik Bougalis

    30. Juli ’13 um 17:55

  • @NikBougalis: Abwärtskompatibilität ist a riesig Last zu tragen. Es gibt Compiler, die ihre Inkompatibilität mit dem Standard aufrechterhalten, nur weil ihre Clients diese inkompatiblen Funktionen verwenden. Dies wäre nur einer dieser Fälle (dh Überlastung verbieten || und Sie werden feststellen, dass Anbieter den Support als Erweiterung beibehalten, weil ihre Kunden ihn verwenden – ob sie ihn verwenden sollten oder nicht, es ist schließlich ihr Geld…)

    – David Rodríguez – dribeas

    30. Juli ’13 um 18:24

  • @NikBougalis Die Rolle des Standards ist nicht gute Praxis zu fördern (und in vielen Fällen tatsächlich genau das Gegenteil bewirkt); es ist die Standardisierung der bestehenden Praxis. Und es gibt heute nichts, was Compiler davon abhalten würde, vor dieser Praxis zu warnen. (Aber es ist nicht schwarz und weiß. Der Standard könnte sie verwerfen, um beispielsweise Compiler-Warnungen zu fördern.)

    – James Kanze

    31. Juli ’13 um 9:05

Ich denke, der Hauptgrund zu dieser Zeit war, dass es sich nicht lohnte, eine neue Syntax nur für diesen Operator zu erfinden. Es gibt kein Token ?:, also müssten Sie dafür eine Reihe spezieller Grammatikregeln erstellen. (Die aktuelle Grammatikregel hat operator gefolgt von einem Operator, bei dem es sich um ein einzelnes Token handelt.)

Da wir (aus Erfahrung) gelernt haben, das Überladen von Operatoren vernünftiger zu verwenden, hat sich herausgestellt, dass wir das Überladen von . wirklich nicht zulassen sollten && und || entweder aus den Gründen, auf die andere Antworten hingewiesen haben, und wahrscheinlich auch nicht mit Operatorkomma (da die überladenen Versionen nicht den Sequenzpunkt haben, den der Benutzer erwartet). Die Motivation, es zu unterstützen, ist also noch geringer als ursprünglich.

  • ‘?’ und ‘:’ werden getrennt, aber die Produktionsregel in der Grammatik wird als Ganzes verarbeitet. Ich habe diesen Operator in der Vergangenheit in yacc implementiert, indem ich Code wie diesen verwendet habe: expr : expr '?' expr ':' expr { $$ = new ConditionalOp($1, $3, $5); };

    – Daniel Frużyński

    19. Nov. 17 um 12:30 Uhr

1641743753 508 Warum ist es nicht moglich den ternaren Operator zu uberladen
JaredPar

Eines der Prinzipien des ternären Operators besteht darin, dass die Wahr/Falsch-Ausdrücke nur basierend auf der Wahrheit oder Falschheit des bedingten Ausdrucks ausgewertet werden.

cond ? expr1 : expr2

In diesem Beispiel expr1 wird nur ausgewertet, wenn cond ist wahr, während expr2 wird nur ausgewertet, wenn cond ist falsch. Wenn wir dies im Hinterkopf behalten, sehen wir uns an, wie eine Signatur für ternäres Überladen aussehen würde (der Einfachheit halber hier feste Typen anstelle einer Vorlage verwenden).

Result operator?(const Result& left, const Result& right) { 
  ...
}

Diese Signatur ist einfach nicht legal, weil sie genau die von mir beschriebene Semantik verletzt. Um diese Methode aufzurufen, müsste die Sprache beides auswerten expr1 und expr2 daher werden sie nicht mehr bedingt ausgewertet. Um ternär zu unterstützen, müsste der Betreiber entweder

  1. Nehmen Sie ein Lambda für jeden Wert, damit es sie bei Bedarf erzeugen kann. Dies würde den aufrufenden Code jedoch notwendigerweise komplizieren, da er die Lambda-Aufrufsemantik berücksichtigen müsste, wenn logisch kein Lambda vorhanden war
  2. Der ternäre Operator müsste einen Wert zurückgeben, um anzugeben, ob der Compiler verwenden soll expr1 oder expr2

BEARBEITEN

Einige mögen argumentieren, dass das Fehlen von Kurzschlüssen in diesem Szenario in Ordnung ist. Der Grund dafür ist, dass Sie in C++ bereits mit den Kurzschluss bei Operatorüberladungen verletzen können || und &&

Result operator&&(const Result& left, const Result& right) { 
  ...
}

Obwohl ich dieses Verhalten selbst für C++ immer noch verblüffend finde.

1641743753 454 Warum ist es nicht moglich den ternaren Operator zu uberladen
Jerry Sarg

Die kurze und genaue Antwort lautet einfach “weil Bjarne sich dafür entschieden hat”.

Obwohl die Argumente darüber, welche Operanden in welcher Reihenfolge ausgewertet werden sollten, eine technisch genaue Beschreibung dessen liefern, was passiert, tragen sie wenig (nicht wirklich) dazu bei, zu erklären, warum dieser spezielle Operator nicht überladen werden kann.

Die gleichen grundlegenden Argumente würden insbesondere auch für andere Operatoren gelten, wie z operator && und operator||. In der integrierten Version jedes dieser Operatoren wird der linke Operand ausgewertet, und zwar genau dann, wenn dies 1 Pro && oder ein 0 Pro ||, wird der rechte Operand ausgewertet. Ebenso wertet der (eingebaute) Kommaoperator seinen linken Operanden aus, dann seinen rechten Operanden.

In einer überladenen Version eines dieser Operatoren beide Operanden werden immer (in nicht spezifizierter Reihenfolge) ausgewertet. Als solche sind sie in dieser Hinsicht im Wesentlichen identisch mit einem überladenen ternären Operator. Sie alle verlieren die gleiche Garantie dafür, welche Operanden in welcher Reihenfolge ausgewertet werden.

Warum Bjarne diese Entscheidung getroffen hat: Ich sehe einige Möglichkeiten. Einer ist, dass der ternäre Operator, obwohl er technisch gesehen ein Operator ist, in erster Linie der Flusskontrolle gewidmet ist if oder while als die meisten anderen Operatoren zu überladen.

Eine andere Möglichkeit wäre, dass es syntaktisch hässlich wäre und den Parser mit etwas wie operator?:, was eine Definition erfordert ?: als Zeichen usw. — alle erfordern ziemlich ernsthafte Änderungen an der C-Grammatik. Zumindest aus meiner Sicht scheint dieses Argument ziemlich schwach zu sein, da C++ bereits ein viel komplexerer Parser als C, und diese Änderung wäre wirklich viel kleiner als viele andere vorgenommene Änderungen.

Das vielleicht stärkste Argument von allen ist einfach, dass es nicht so aussah, als würde es viel bewirken. Da es in erster Linie der Flusskontrolle gewidmet ist, ist es unwahrscheinlich, dass eine Änderung seiner Funktion für einige Arten von Operanden etwas sehr Nützliches bewirkt.

Aus dem gleichen Grund, warum Sie wirklich nicht (obwohl Sie es können) überladen sollten && oder || Operatoren – dies würde Kurzschlüsse bei diesen Operatoren deaktivieren (wobei nur der notwendige Teil und nicht alles bewertet wird), was zu schwerwiegenden Komplikationen führen kann.

.

223110cookie-checkWarum ist es nicht möglich, den ternären Operator zu überladen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy