Das meiste ärgerliche Parse: warum nicht A a (()); Arbeit?
Unter den vielen Dingen, Stack Overflow, hat mich gelehrt, es ist, was ist bekannt als die "most vexing parse", die klassisch demonstrierten mit einer Zeile wie
A a(B()); //declares a function
Während dies für die meisten, intuitiv zu sein scheint, die Erklärung eines Objekts a
Typ A
, wobei eine vorübergehende B
- Objekt als Konstruktor-parameter, es ist eigentlich eine Erklärung der Funktion a
Rückkehr A
, wobei ein Zeiger auf eine Funktion, die zurückgibt B
und selbst benötigt keine Parameter. Ebenso die Linie
A a(); //declares a function
fällt auch unter die gleiche Kategorie, da statt einem Objekt, eine Funktion deklariert. Nun, im ersten Fall, der übliche workaround für dieses Problem ist das hinzufügen von einen zusätzlichen Satz von Klammern/Klammern um die B()
, da der compiler dann interpretieren Sie es als die Deklaration eines Objekts
A a((B())); //declares an object
Jedoch im zweiten Fall, das gleiche zu tun, führt zu einem compile-Fehler
A a(()); //compile error
Meine Frage ist, warum? Ja, ich bin mir sehr wohl bewusst, dass die richtige 'workaround' ist zu ändern, um A a;
, aber ich bin neugierig zu wissen, was es ist, dass die zusätzlichen ()
bedeutet, dass der compiler im ersten Beispiel, die dann nicht funktioniert, wenn das erneute anwenden es im zweiten Beispiel. Ist die A a((B()));
Abhilfe einer bestimmten Ausnahme in der SCHRIFTLICHEN standard?
(B())
ist nur eine C++ - Ausdruck, nichts mehr. Es ist nicht jede Art von Ausnahme. Der einzige Unterschied ist, dass es macht ist, dass es gibt keine Möglichkeit, kann es evtl. analysiert, wie eine Art, und so ist es nicht. Ein();
ist nicht der gleichen Kategorie. Für die compiler, es gibt keine andere Weise, Sie zu analysieren: Ein Initialisierer an diesem Ort besteht niemals mit leeren Klammern, so ist dies immer eine Funktionsdeklaration. Ein();
ist nicht ein Beispiel most vexing parse. Es ist einfach eine Funktion, die Erklärung, genau wie in C. A;
" ist falsch. Das wird nicht geben Sie die Initialisierung der ein POD-Typ. Um intitialization schreiben {};
. InformationsquelleAutor der Frage GRB | 2009-09-15
Du musst angemeldet sein, um einen Kommentar abzugeben.
Gibt es keine aufgeklärte Antwort, es ist nur, weil es ist nicht definiert, wie gültige syntax der Sprache C++... Also es ist so, per definition der Sprache.
Wenn Sie einen Ausdruck innerhalb, dann ist es gültig. Zum Beispiel:
Erfahren Sie mehr darüber, wie Sprachen definiert sind, und wie Compiler arbeiten, sollten Sie lernen, über Formale Sprache Theorie oder genauer Kontext-Freie Grammatiken (CFG) und Verwandte Materialien, wie finite-state-machines. Wenn Sie interessiert sind, an, dass, obwohl die wikipedia-Seiten nicht genug sein, müssen Sie Holen Sie sich ein Buch.
InformationsquelleAutor der Antwort Brian R. Bondy
Die endgültige Lösung für dieses Problem ist, sich zu bewegen, um die C+11 uniform initialization syntax, wenn Sie können.
http://www.stroustrup.com/C++11FAQ.html#uniform-init
InformationsquelleAutor der Antwort David
C-Funktion declarators
Erstens, es ist C. In C
A a()
ist Funktionsdeklaration. Zum Beispielputchar
hat die folgende Erklärung ab. Normalerweise sind solche Erklärungen sind gespeichert in header-Dateien, aber nichts hält dich davon ab, schreiben Sie Sie manuell, wenn Sie wissen, wie die Deklaration der Funktion sieht folgendermaßen aus. Die argument-Namen sind optional in den Erklärungen, also habe ich es weggelassen in diesem Beispiel.Dadurch können Sie code schreiben, wie diese.
C auch können Sie definieren Funktionen, die Funktionen als Argumente, mit schön lesbaren syntax, das aussieht wie ein Funktionsaufruf (gut, es ist lesbar, solange Sie nicht zurückkehren, einen Zeiger auf Funktion).
Als ich erwähnte, C ermöglicht das weglassen argument-Namen in header-Dateien, daher ist der
output_result
Aussehen würde, wie dies in der header-Datei.Ein argument im Konstruktor
Erkennst du nicht? Nun, lassen Sie mich daran erinnern.
Yep, es ist genau die gleiche Funktion Erklärung.
A
istint
,a
istoutput_result
, undB
istint
.Können Sie leicht feststellen, einen Konflikt von C mit neuen Eigenschaften von C++. Um genau zu sein, die Konstruktoren als Klassenname und Klammern, und die Alternative Erklärung-syntax mit
()
statt=
. Durch design, C++ versucht, um die Kompatibilität mit C-code, und daher es zu tun hat mit diesem Fall - auch wenn praktisch niemand kümmert sich. Deshalb werden alte C-Funktionen haben Vorrang über die neue C++ - features. Die Grammatik-Erklärungen versucht, den Namen der Funktion, bevor Rückgriff auf die neue syntax mit()
wenn es fehlschlägt.Wenn eine dieser Funktionen nicht existieren würde, oder hatte eine andere syntax (wie
{}
in C++11), würde diese Frage nie passiert syntax mit einem argument.Nun mögen Sie sich Fragen, warum
A a((B()))
funktioniert. Nun, lassen Sie uns erklärenoutput_result
mit nutzlosen Klammern.Funktioniert es nicht. Die Grammatik erfordert die variable nicht in Klammern.
Jedoch C++ - standard erwartet Ausdruck hier. In C++ können Sie den folgenden code schreiben.
Und den folgenden code.
C++ erwartet Ausdruck in inneren Klammern... naja... Ausdruck, im Gegensatz zu den Typ C erwartet. Klammern bedeuten nichts hier. Jedoch, durch das einfügen nutzlos Klammern, die C-Funktion-Deklaration wird nicht abgestimmt, und die neue syntax angepasst werden kann, richtig (die einfach erwartet einen Ausdruck wie
2 + 2
).Mehr Argumente im Konstruktor
Sicherlich ein argument ist nett, aber was ist mit zwei? Es ist nicht so, dass Konstruktoren nur ein argument. Ein built-in-Klassen, die zwei Argumente nimmt, ist
std::string
Dies ist alles gut und schön (technisch, es hätte am meisten ärgerlich analysieren, wenn es geschrieben würde, als
std::string wat(int(), char())
, aber seien wir mal ehrlich - wer würde Sie schreiben? Aber nehmen wir an, dieser code ist mit einem äußerst lästigen problem. Sie würden davon ausgehen, dass Sie um alles in Klammern.Nicht ganz so.
Ich bin mir nicht sicher, warum der g++ versucht zu konvertieren
char
zuconst char *
. So oder so, wird der Konstruktor aufgerufen wurde, mit nur einem Wert vom Typchar
. Es ist keine überlast, die ein argument vom Typchar
, daher ist der compiler verwirrt. Sie Fragen sich vielleicht - warum wird das argument vom Typ char?Ja,
,
hier ist ein Komma-operator. Der Komma-operator nimmt zwei Argumente und gibt das Recht-side-argument. Es ist nicht wirklich nützlich, aber es ist etwas bekannt zu sein für meine Erklärung.Statt, zu lösen die kniffligsten analysieren, ist der folgende code notwendig.
Die Argumente stehen in Klammern, nicht der gesamte Ausdruck. In der Tat, nur einer der Ausdrücke muss in Klammern, wie es ist genug, um zu brechen aus der C-Grammatik leicht auf die C++ - Funktion. Dinge bringt uns zu dem Punkt, null Argumente.
Null Argumente im Konstruktor
Wie Sie vielleicht bemerkt haben
eighty_four
Funktion in meine Erklärung.Ja, das ist auch geprägt durch die meisten vexing parse. Es ist eine gültige definition, und eine, die Sie wahrscheinlich gesehen haben, wenn Sie die erstellte header-Dateien (und Sie sollten). Hinzufügen von Klammern nicht zu beheben.
Warum ist das so? Gut,
()
ist kein Ausdruck. In C++, die Sie haben, um einen Ausdruck zwischen den Klammern. Sie können nicht schreibenauto value = ()
in C++, da()
nichts zu bedeuten hat (und selbst wenn es Tat, wie leere Tupel (siehe Python), wäre es ein argument, nicht null). Praktisch, dass bedeutet, Sie können verwenden die Kurzform syntax ohne die mithilfe von C++11 ist{}
syntax, da gibt es keine Ausdrücke, die setzen Sie in Klammern und C-Grammatik für Funktionsdeklarationen wird immer gelten.InformationsquelleAutor der Antwort xfix
Könnten Sie stattdessen
verwenden
InformationsquelleAutor der Antwort user265149
Den innersten Klammern in deinem Beispiel wäre ein Ausdruck, und in der C++ - Grammatik definiert eine
expression
eineassignment-expression
oder anderenexpression
gefolgt von einem Komma und einem anderenassignment-expression
(Anhang A. 4 - Grammatik Zusammenfassung/Ausdrücke).Die Grammatik weiter definiert eine
assignment-expression
als eine von mehreren anderen Arten von Ausdruck, von denen keines kann nichts (oder nur Leerzeichen).Also der Grund, warum Sie nicht haben können
A a(())
ist einfach, weil die Grammatik nicht erlauben. Aber, ich kann nicht beantworten, warum die Leute, die das erstellte C++ trifft nicht zu, dass diese insbesondere die Verwendung von leeren Klammern als eine Art Sonderfall - ich denke, dass Sie lieber nicht in solch einem speziellen Fall, wenn es eine vernünftige alternative.InformationsquelleAutor der Antwort Michael Burr