Warum verwendet der Postfix-Inkrement-Operator einen Dummy-Parameter?

Lesezeit: 8 Minuten

Warum verwendet der Postfix Inkrement Operator einen Dummy Parameter
Naruto

Sehen Sie sich diese Funktionssignaturen an:

 class Number {
 public:
   Number& operator++ ();    // prefix ++
   Number  operator++ (int); // postfix ++
 }; 

Prefix nimmt keine Parameter an, aber Postfix tut es. Wieso den? Ich dachte, wir können sie an verschiedenen Rückgabetypen erkennen.

  • Der nur time C++-Überladungen nach Rückgabetyp ist für den Typumwandlungsoperator.

    – Mike DeSimone

    26. August ’10 bei 12:38

  • @Mike: Ich glaube nicht, dass in diesem Fall die Überlastungsauflösung ins Spiel kommt.

    – Dennis Zickefoose

    26. August ’10 um 13:36

  • Guter Punkt. Ich habe es immer als “Überlastung des Typecast-Operators” betrachtet, aber vielleicht gibt es einen besseren Begriff.

    – Mike DeSimone

    26. August ’10 um 14:19

  • Mein Eindruck war immer, dass es keinen einzigen Typecast-Operator gibt. Vielmehr gibt es viele Typumwandlungsoperatoren; die Umwandlung in jeden Zieltyp ist ein eigener Operator.

    – Tyler McHenry

    26. August ’10 bei 16:27

1641774015 362 Warum verwendet der Postfix Inkrement Operator einen Dummy Parameter
Omnifarious

Präfix und Postfix ++ sind verschiedene Betreiber. Mit dem Standard Foo operator symbol(Foo &) Style-Deklaration gab es keine offensichtliche Möglichkeit, die beiden zu unterscheiden. Anstatt eine neue Syntax zu entwickeln wie Foo symbol operator(Foo &) was es im Gegensatz zu allen anderen Operatoren zu einem Sonderfall machen würde und wahrscheinlich etwas mühsam zu analysieren wäre, wollten die Sprachdesigner eine andere Lösung.

Die von ihnen gewählte Lösung war etwas bizarr. Sie stellten fest, dass alle anderen ‘Postfix’-Operatoren (dh Operatoren, die nach einem ihrer Operanden auftraten) eigentlich Infix-Operatoren waren, die zwei Argumente akzeptierten. Zum Beispiel einfach alt +, / oder >. Auf dieser Grundlage entschieden die Sprachdesigner, dass ein zufälliges Dummy-Argument eine gute Möglichkeit wäre, zwischen Präfix und Postfix zu unterscheiden ++.

IMHO, es ist eine der seltsameren Entscheidungen, die während der Entwicklung von C++ getroffen wurden. Aber da hast du es.

Und Sie können sie aus zwei Gründen nicht nach dem Rückgabetyp unterscheiden.

Der erste besteht darin, dass Funktionen in C++ beim Rückgabetyp nicht überladen werden können. Sie können nicht zwei Funktionen mit identischen Namen und Parametertyplisten, aber unterschiedlichen Rückgabewerten haben.

Die zweite ist, dass die Methode nicht robust oder flexibel genug wäre, um alle möglichen Implementierungen von Präfix und Postfix zu handhaben ++.

Zum Beispiel möchten Sie vielleicht ein Postfix ++ das einen Verweistyp zurückgegeben hat, wenn der einzige Grund, warum Sie ihn jemals aufgerufen haben, darin bestand, einen Nebeneffekt aufzurufen, der nichts mit dem Wert der Variablen zu tun hat, auf die Sie ihn angewendet haben. Meiner Meinung nach wäre das eine sehr schlechte Implementierung, aber bei C++ geht es nicht darum zu beurteilen, welche Arten von dummem Code Sie schreiben möchten, sondern darum, Ihnen zu ermöglichen, jeden Code zu schreiben, der Ihrer Meinung nach für die Situation angemessen ist. Und Sie zwingen, einen bestimmten Rückgabetyp für das Präfix zu verwenden ++ und postfix ++ würde diesem Geist widersprechen.

  • Als Randnotiz habe ich diese Informationen aus “The Design and Evolution of C++” von Bjarne Stroustroup entnommen. Ich würde es empfehlen, wenn Sie wirklich verstehen möchten, warum C++ so ist, wie es ist. Das Wachsen einer Sprache durch Akkretion in einer Umgebung, in der Abwärtskompatibilität sehr wichtig ist, führt zu vielen seltsamen Dingen.

    – Omnifarious

    26. August ’10 bei 12:36

  • Wirklich gute Alternativen gibt es allerdings nicht. Sie könnten einen Pseudo-Operator erfinden (zB operator +++), die die Leute vergessen oder falsch verstehen oder ein Schlüsselwort hinzufügen (z. B. post operator ++) oder verzichten Sie auf die Operatoren selbst und verwenden Sie stattdessen spezielle Namen (z. B. Pythons __add__ und Freunde). Alle sehen schlimmer aus als die Dummy-Variable.

    – Mike DeSimone

    26. August ’10 bei 12:52

  • Ja, operator post_increment wäre viel einfacher zu lesen, aber dann post_increment wird zu einem reservierten Wort, das möglicherweise Compiler oder andere Programme zerstört, die diesen Namen bereits verwendet haben. Daher ist die Python-Konvention “Namen mit führenden doppelten Unterstrichen alle reserviert”. In der Geschichte von XHTML finden Sie ein Beispiel dafür, warum man in einem neuen Standard nicht massive Abwärtskompatibilitätsbrüche verursachen sollte.

    – Mike DeSimone

    26. August ’10 um 14:15

  • @Mike: Das musst du nicht machen post_increment ein neues Stichwort. Wenn Sie eine neue Syntax für “explizite” Operatornamen einführen, können Sie eine Regel hinzufügen wie: 'operator' 'explicit' <identifier> (<args>) wobei bezeichner einer der expliziten Operatornamen sein muss (wie ‘post_increment’, ‘pre_increment’ usw.). Aus der Sicht des Parsens müssen sie keine reservierten Wörter sein, weil sie dann nur “besonders” sind operator explicit Position. Das ist ganz einfach umzusetzen!

    – Nordischer Mainframe

    26. August ’10 um 14:59

  • Sobald Sie eine typedef haben, die lautet typedef int post; Du kannst schreiben R operator++(post); was meiner Meinung nach nicht schlecht aussieht.

    – Johannes Schaub – litb

    27. August ’10 bei 0:07

Warum verwendet der Postfix Inkrement Operator einen Dummy Parameter
Nordischer Mainframe

Es steht Ihnen frei, operator++ einen beliebigen Rückgabetyp zuzuweisen, daher gibt es keine Möglichkeit, Postfix und Präfix dadurch zu unterscheiden. Der Compiler braucht also einen Hinweis.

OTOH, ich weiß nicht, warum dies nicht nur in der Syntax möglich war:

//prefix
int& ++operator (); 
//postfix
int& operator++ (); 

Schließlich hat die Nachahmung der Verwendung in Deklarationen in C und C++ Tradition.

PS Andere Poster: Das hat nichts mit Überladen durch den Rückgabetyp zu tun. Postfix und Präfix ++/– sind zwei verschiedene Namen. Eine Überlastung muss nicht behoben werden x++ oder ++x, weil ganz klar ist, welcher Name gemeint ist.

  • ist es, könnten sie es so gemacht haben, wie Sie es vorgeschlagen haben 🙂 .. also nur für die Compiler-Unterscheidung schreiben sie Parameter richtig? eine andere Frage, warum sie Postfix gemacht haben, um Parameter zu akzeptieren, warum nicht Präfix? sie hätten sich vertauschen können, irgendein spezifischer Unterschied?

    – Naruto

    26. August ’10 bei 12:11

  • Das hätte wohl besondere Zuwendungen in der Grammatik erfordert, die ohnehin schon so komplex ist. Außerdem wäre der nächste logische Schritt, die anderen unären Operatoren aus Konsistenzgründen mit der Präfix-/Postfix-Notation abzugleichen. Was wäre in diesem Fall? T &operator() bedeuten?

    – Dennis Zickefoose

    26. August ’10 um 12:16

  • @Shadow: Der zusätzliche Parameter für Postfix dient als visuelle Erinnerung daran, dass die Aktion auf der rechten Seite stattfindet.

    – Nordischer Mainframe

    26. August ’10 um 12:16

  • Überladen war nicht möglich, da ++operator denn dann müssten Sie, um konsistent zu sein, alle standardmäßigen unären Operatoren (+, -, !, *, ~) als Präfixnotation verwenden, und dann *operator wäre zweideutig, da int *operator() könnte aussehen wie “Funktionaler Operator, der Zeiger auf int zurückgibt” anstelle von “Zeiger-Dereferenzierungsoperator, der int zurückgibt”. Außerdem ist der Parser einfacher zu implementieren (und besser beim Abfangen von Fehlern), wenn das Schlüsselwort operator kommt immer zuerst.

    – Mike DeSimone

    26. August ’10 bei 12:44


  • @Mike: die Mehrdeutigkeit ist der Grund. Wenn ++operator erlaubt wäre, wäre das Lexing viel schwieriger (was in diesem Fall heißt: um Größenordnungen langsamer).

    – Fabio Fracassi

    26. August ’10 um 13:20

1641774015 73 Warum verwendet der Postfix Inkrement Operator einen Dummy Parameter
Fredoverflow

Direkt aus Bjarnes Mund:

Das mag sowohl zu süß als auch zu subtil sein, aber es funktioniert, erfordert keine neue Syntax und hat eine Logik zum Wahnsinn. Andere unäre Operatoren sind Präfixe und nehmen keine Argumente an, wenn sie als Memberfunktionen definiert sind. Der “seltsame” und unbenutzte Dummy int -Argument wird verwendet, um die ungeraden Postfix-Operatoren anzugeben. Mit anderen Worten, im Postfix-Fall, ++ steht zwischen dem ersten (realen) Operanden und dem zweiten (Dummy-)Argument und ist somit postfix.

Diese Erklärungen sind notwendig, da der Mechanismus einzigartig und daher ein bisschen wie eine Warze ist. Hätte ich die Wahl gehabt, hätte ich wahrscheinlich die eingeführt prefix und postfix Keywords, aber das schien damals nicht machbar. Der einzige wirklich wichtige Punkt ist jedoch, dass der Mechanismus funktioniert und von den wenigen Programmierern, die ihn wirklich brauchen, verstanden und verwendet werden kann.

Übrigens meiner Meinung nach nur Präfix ++ sollte vom Programmierer überlastbar sein und postfix ++ sollte vom Compiler automatisch generiert werden. Stimmt mir jemand zu?

  • Stimmt mir jemand zu? – #include <boost/operators.hpp>

    – Onkel Bens

    26. August ’10 um 16:05

  • Nicht so, wie die Sprache derzeit eingerichtet ist, nein. Ich denke, es wäre nett, wenn wir nach 0x Standardoperatoren verwenden und den Compiler aus anderen von Ihnen definierten Operatoren erstellen lassen könnten.

    – Dennis Zickefoose

    26. August ’10 um 17:16

  • Sie wissen, dass ich Ihnen nicht zustimmte… Aber das scheint die einzige Möglichkeit zu sein, dieses Problem der Überlastungsauflösung zu vermeiden. Ich bin mir nur nicht sicher, wie Sie das bei Objekten handhaben würden? Anstelle des Objekts müsste der Compiler eine Kopie des Objekts übergeben, was bei Objekten, die keinen Kopierkonstruktor haben, heikel werden kann.

    – Jonathan Mee

    5. Mai ’16 um 12:27

Wenn ich meine Druther hätte, würden Postinkrement und viele Sequenzpunktoperatoren in zwei oder drei Teile gespalten; im Fall von Postinkrement eine Anweisung wie “a=(b++ + c++);” würde effektiv übersetzt werden als “a=postinc1(b)+postinc1(c); postinc2(b); postinc2(c);”; der zweite Teil des Postinkrement wäre eine void-Funktion. In der tatsächlichen Implementierung sollten die postinc2()-Aufrufe wahrscheinlich häufig auftreten, während andere Ergebnisse auf dem Auswertungsstapel liegen; das sollte für einen Compiler nicht allzu schwer zu implementieren sein.

Im Fall von “&&” oder “||” würde der erste Teil des Operators nur den linken Operanden bearbeiten; wenn es ungleich null (für &&) oder ungleich null (für ||) zurückgibt, dann würde der zweite Teil auf beiden Operanden operieren.

Im Fall von “?”https://stackoverflow.com/”:” würde der erste Teil des Operators nur mit dem ersten Operanden arbeiten. Wenn es einen Wert ungleich Null zurückgibt, würde der zweite Teil mit dem ersten und dem zweiten Parameter arbeiten; andernfalls würde der dritte Teil mit dem ersten und dritten Parameter arbeiten.

Machen irgendwelche Sprachen so etwas? Es erscheint seltsam, dass C++ die Umdefinition von Operatoren auf eine Weise zulässt, die das Sequenzverhalten unterbricht, aber nicht zulässt, dass sie so umdefiniert werden, dass es beibehalten wird.

Der Compiler verwendet das int-Argument, um zwischen den Präfix- und Postfix-Inkrementoperatoren zu unterscheiden. Für implizite Aufrufe ist der Standardwert null, also macht er eigentlich keinen so großen Unterschied in der Funktionalität des überladenen Operators…

.

255270cookie-checkWarum verwendet der Postfix-Inkrement-Operator einen Dummy-Parameter?

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

Privacy policy