Dieses Problem ist bekannt als the most vexing parse, die genau beschreibt Ihre Situation, wo der Parser nicht wissen Sie wollen eine Funktionsdeklaration oder die Instanziierung eines Objekts. Es ist mehrdeutig in dem Sinne, dass für einen Menschen ein gegebenes Stück Code X, aber für den Compiler tut es eindeutig Y.
Ein Weg, um es zu bekommen ist die list initialization Syntax:
B var{A()}; // note the use of brackets
Das ist nicht mehr zweideutig, und es wird den Konstruktor aufrufen, wie man wollte. Sie können es auch in A
oder in beide verwenden:
B var(A{});
B var{A{}};
Nun, warum ist es nicht eindeutig? Nehmen Sie die Deklaration eines Funktionsparameter zum Beispiel, dass ein Zeiger funktionieren:
int foo(int (*bar)());
Hier wird der Parameter ist vom Typ Zeiger auf Funktion, die keine Argumente annimmt und hat Typ int zurück. Ein anderer Weg, Zeiger auf Funktion zu erklären ist durch die Klammern im declarator Weglassen:
int foo(int bar());
, die noch einen Zeiger auf den vorherigen funktionieren identisch erklärt. Da wir im Zusammenhang mit der Deklaration von Parametern stehen (parameter-declaration-clause), wird die Grammatik, die analysiert wird, eine type-id, die teilweise auf abstract-declarator aufgebaut ist. Daher können wir die Kennung entfernen:
int foo(int());
Und wir am Ende immer noch mit dem gleichen Typ.
Wenn das gesagt alle, lassen Sie uns Ihren Code untersuchen und vergleichen Sie es mit den obigen Beispielen:
B var(A());
Wir haben etwas, das wie eine variable Deklaration vom Typ sieht B
mit A()
initialisiert. So weit, ist es gut. Aber warte, du hast gesagt, das kompiliert nicht!
Die Fehlermeldung erscheint, dass es var wie eine Funktionsdeklaration behandelt.
var
ist in der Tat eine Funktionsdeklaration, obwohl es Ihnen an erster Stelle nicht so aussah. Dieses Verhalten ist aufgrund [dcl.ambig.res]/1:
[...] die Auflösung jedes Konstrukt zu berücksichtigen, die möglicherweise eine Erklärung einer Erklärung sein könnten.
Und dieser Satz gilt hier. Im Rückblick auf den vorherigen Beispielen:
int foo(int());
, die genauso zweideutig wie Ihr Code: foo
könnte möglicherweise eine Erklärung sein, so dass die Auflösung dieser als ein zu interpretieren ist. Ihr könnte möglicherweise auch eine Erklärung sein, so dass es die gleiche Auflösung hat.
Der Standard hat ein paar Beispiele für diese Fälle auf [dcl.ambig.res]/1, example #1, und gibt auch einige Tipps, wie sie auf [dcl.ambig.res]/1, note #1 eindeutig zu machen:
[Anmerkung: Eine Erklärung explizit durch Hinzufügen von Klammern um das Argument vereindeutigt werden kann . Die Ambiguität kann vermieden werden, indem die Initialisierungssyntax für die Kopie oder die Initialisierung der Liste verwendet wird oder indem eine Nichtfunktionsart verwendet wird. - Endnote ]
[Beispiel:
struct S {
S(int);
};
void foo(double a) {
S w(int(a)); // function declaration
S x(int()); // function declaration
S y((int(a))); // object declaration
S y((int)a); // object declaration
S z = int(a); // object declaration
}
- Ende Beispiel ]