Betrachten Sie den folgenden Code:
%Vor% Also wird der Ausdruck {m}
als rvalue-Referenz behandelt und deshalb kann dieser Code nicht kompiliert werden.
Stimmt das, dass {object}
immer ein temporäres Objekt erzeugt?
Wenn nein, wie kann man sicher sein, wenn es passiert? Wenn ja, beachten Sie bitte folgenden Code:
%Vor% Hier gibt es überhaupt kein Problem, also was ist der Unterschied zwischen {m}
vom ersten Beispiel und {p}
vom zweiten?
Compiler (GCC 4.8.1) Ergebnisse (erstes Beispiel):
%Vor%Was ist der Typ von
{object}
?
Das hängt vom Kontext ab. In einigen Situationen, z. B. beim Erstellen eines Typs mit einem std::initializer_list
-Parameter, wird der Typ std::initializer_list<decltype(object)>
verwendet. In anderen Fällen wird es verwendet, um Elemente eines Aggregats oder eines anderen Typs zu initialisieren. In diesem Fall hat die syntaktische Form {object}
nicht einen Typ an sich .
Stimmt das, dass
{object}
immer ein temporäres Objekt erzeugt?
Nein, und in Ihrem Fall sollte es nicht. Dies war ein Fehler in der C ++ 11 Spezifikation in Bezug auf die Reihenfolge der Klauseln, die die Initialisierung der Liste spezifizieren. Die alte Formulierung bedeutete, dass Ihr Aufruf zur Konstruktion eines Temporären führte (das aufgrund des nichtkonstanten Referenzparameters schlecht gebildet ist), aber unter den neuen Regeln bindet sich die Referenz an das einzelne Initialisierungslistenelement. Ihr alter Compiler implementiert die alte Formulierung, während neuere Compiler das festgelegte Verhalten implementieren.
Hier gibt es überhaupt kein Problem, also was ist der Unterschied zwischen {m} vom ersten Beispiel und {p} vom zweiten?
Der Unterschied besteht darin, dass {m}
verwendet wird, um den M
-Parameter von foo
zu initialisieren (unter der alten Formulierung ungültig), aber {p}
initialisiert das I
-Member. Als solches wird p
als Argument für den I
-Konstruktor genommen, bindet sich an den M&
-Parameter, und da p
ein Lvalue ist, ist alles in Ordnung und gut.
Stimmt dies, dass {Objekt} immer ein temporäres Objekt erzeugt?
Nein (weiterlesen).
Beide Snippets sind gültig (Sie sollten einen aktuellen Compiler verwenden) und werden erfolgreich kompiliert.
Der {p}
-Fall fällt in [over.match.list]/p1
Wenn Objekte des Nicht-Aggregat-Klassentyps T in der Liste initialisiert werden, sodass [dcl.init.list] angibt, dass die Überladungsauflösung gemäß den Regeln in diesem Abschnitt ausgeführt wird, wählt die Überladungsauflösung den Konstruktor in zwei Phasen aus:
(1.1) Anfänglich sind die Kandidatenfunktionen die Konstruktoren der Initialisierungsliste ([dcl.init.list]) der Klasse T und die Argumentliste besteht aus der Initialisierungsliste als einzelnes Argument.
(1.2) Wenn kein ausführbarer Initialisierungslistenkonstruktor gefunden wird, wird die Überladungsauflösung erneut ausgeführt, wobei die Kandidatenfunktionen alle Konstruktoren der Klasse T sind und die Argumentliste aus den Elementen der Initialisierungsliste besteht.
Speziell in (1.2), während {m}
eine Listeninitialisierung für den anderen Fall ist.
Tags und Links c++