War es nicht möglich, dasselbe Ergebnis zu erzielen, ohne eine Variable explizit zu deklarieren auto
?
Ich werde Ihre Frage leicht umformulieren, damit Sie verstehen, warum Sie Folgendes benötigen auto
:
War es nicht möglich, dasselbe Ergebnis zu erzielen, ohne explizit einen Typplatzhalter zu verwenden ?
War es nicht möglich ? Natürlich war es "möglich". Die Frage ist, ob sich die Mühe lohnt, dies zu tun.
Die meisten Syntaxen in anderen Sprachen, die keine Typnamen haben, funktionieren auf zwei Arten. Es gibt den Go-ähnlichen Weg, bei dem name := value;
eine Variable deklariert wird. Und es gibt die Python-ähnliche Methode, bei der name = value;
eine neue Variable deklariert wird, wenn name
sie zuvor nicht deklariert wurde.
Nehmen wir an, dass es keine syntaktischen Probleme beim Anwenden einer der beiden Syntax auf C ++ gibt (obwohl ich bereits sehen kann, dass in C ++ identifier
gefolgt von :
"make a label" bedeutet). Was verlieren Sie also im Vergleich zu Platzhaltern?
Nun, ich kann das nicht mehr tun:
auto &name = get<0>(some_tuple);
Siehe, auto
bedeutet immer "Wert". Wenn Sie eine Referenz erhalten möchten, müssen Sie explizit a verwenden &
. Und es wird zu Recht nicht kompiliert, wenn der Zuweisungsausdruck ein Wert ist. Keine der zuweisungsbasierten Syntaxen kann zwischen Referenzen und Werten unterscheiden.
Sie können jetzt festlegen, dass solche Zuweisungssyntaxen Referenzen ableiten, wenn der angegebene Wert eine Referenz ist. Aber das würde bedeuten, dass Sie nicht tun können:
auto name = get<0>(some_tuple);
Dies kopiert aus dem Tupel und erstellt ein Objekt unabhängig von some_tuple
. Manchmal ist es genau das, was Sie wollen. Dies ist umso nützlicher, wenn Sie sich vom Tupel mit entfernen möchten auto name = get<0>(std::move(some_tuple));
.
OK, vielleicht könnten wir diese Syntax ein wenig erweitern, um diese Unterscheidung zu berücksichtigen. Vielleicht &name := value;
oder &name = value;
würde bedeuten, eine Referenz wie abzuleiten auto&
.
OK, gut. Was ist damit:
decltype(auto) name = some_thing();
Oh, das stimmt; C ++ hat tatsächlich zwei Platzhalter: auto
unddecltype(auto)
. Die Grundidee dieses Abzugs ist, dass es genau so funktioniert, als ob Sie es getan hätten decltype(expr) name = expr;
. Wenn some_thing()
es sich in unserem Fall um ein Objekt handelt, wird daraus ein Objekt abgeleitet. Wenn some_thing()
es sich um eine Referenz handelt, wird eine Referenz abgeleitet.
Dies ist sehr nützlich, wenn Sie im Vorlagencode arbeiten und nicht genau wissen, wie hoch der Rückgabewert einer Funktion sein wird. Dies ist ideal für die Weiterleitung und ein wesentliches Werkzeug, auch wenn es nicht weit verbreitet ist.
Jetzt müssen wir unsere Syntax erweitern. name ::= value;
bedeutet "mach was decltype(auto)
macht". Ich habe kein Äquivalent für die Pythonic-Variante.
Ist es bei dieser Syntax nicht einfach, versehentlich falsch zu tippen? Nicht nur das, es ist kaum selbstdokumentierend. Selbst wenn Sie es noch nie gesehen decltype(auto)
haben, ist es groß und offensichtlich genug, dass Sie zumindest leicht erkennen können, dass etwas Besonderes los ist. Während der visuelle Unterschied zwischen ::=
und :=
minimal ist.
Aber das ist Meinungsmaterial; Es gibt wesentlichere Fragen. All dies basiert auf der Verwendung der Zuweisungssyntax. Nun ... was ist mit Orten, an denen Sie die Zuweisungssyntax nicht verwenden können? So was:
for(auto &x : container)
Ändern wir das in for(&x := container)
? Denn das scheint etwas zu sagen , sehr verschieden von bereichsbasierten for
. Es sieht so aus, als wäre es die Initialisiereranweisung einer regulären for
Schleife, keine bereichsbasierte for
. Es wäre auch eine andere Syntax als bei nicht abgeleiteten Fällen.
Außerdem ist die Kopierinitialisierung (mit =
) in C ++ nicht dasselbe wie die Direktinitialisierung (mit Konstruktorsyntax). Funktioniert also name := value;
möglicherweise nicht in Fällen, in denen auto name(value)
dies der Fall wäre.
Sicher, Sie könnten deklarieren, dass :=
die Direktinitialisierung verwendet wird, aber das wäre ziemlich inkongruent mit dem Verhalten von C ++.
Außerdem gibt es noch eine Sache: C ++ 14. Es gab uns eine nützliche Abzugsfunktion: den Abzug vom Rückgabetyp. Dies basiert jedoch auf Platzhaltern. for
Ähnlich wie bei einem Bereich basiert es im Wesentlichen auf einem Typnamen, der vom Compiler ausgefüllt wird, und nicht auf einer Syntax, die auf einen bestimmten Namen und Ausdruck angewendet wird.
Alle diese Probleme stammen aus derselben Quelle: Sie erfinden eine völlig neue Syntax zum Deklarieren von Variablen. Platzhalterbasierte Deklarationen mussten keine neue Syntax erfinden . Sie verwenden genau die gleiche Syntax wie zuvor. Sie verwenden lediglich ein neues Schlüsselwort, das sich wie ein Typ verhält, aber eine besondere Bedeutung hat. Dies ermöglicht es ihm, im bereichsbezogenen for
und für den Rückzugsartabzug zu arbeiten. Es ist das, was es erlaubt, mehrere Formen zu haben ( auto
vs. decltype(auto)
). Und so weiter.
Platzhalter funktionieren, weil sie die einfachste Lösung für das Problem darstellen und gleichzeitig alle Vorteile und die Allgemeingültigkeit der Verwendung eines tatsächlichen Typnamens beibehalten. Wenn Sie eine andere Alternative gefunden haben, die so universell funktioniert wie Platzhalter, ist es höchst unwahrscheinlich, dass sie so einfach wie Platzhalter ist.
Es sei denn, es wurden nur Platzhalter mit unterschiedlichen Schlüsselwörtern oder Symbolen geschrieben ...