Ich glaube, dass das Problem die Instanziierung von
ist %Vor%sind, soweit es die Sprache betrifft, keine copy / move-Konstruktoren, und daher können Aufrufe an sie vom Compiler nicht gelöscht werden. Aus §12.8 [class.copy] / p2-3, Hervorhebung hinzugefügt und Beispiele weggelassen:
Ein Nicht-Template-Konstruktor für die Klasse
X
ist ein Kopierkonstruktor if Der erste Parameter ist vom TypX&
,const X&
,volatile X&
oderconst volatile X&
. und entweder gibt es keine anderen Parameter oder sonst alle Andere Parameter haben Standardargumente (8.3.6).Ein Nicht-Template-Konstruktor für die Klasse
X
ist ein move-Konstruktor if Der erste Parameter ist vom TypX&&
,const X&&
,volatile X&&
oderconst volatile X&&
, und entweder gibt es keine anderen Parameter oder sonst alle Andere Parameter haben Standardargumente (8.3.6).
Mit anderen Worten, ein Konstruktor, der eine Vorlage ist, kann niemals ein Kopier- oder Verschiebekonstruktor sein.
Die Rückgabewert-Optimierung ist ein Spezialfall der Kopie-Elision, die als (§12.8 [class.copy] / p31) beschrieben wird:
Wenn bestimmte Kriterien erfüllt sind, darf eine Implementierung ausgelassen werden die Kopie / Move-Konstruktion eines Klassenobjekts, selbst wenn der Konstruktor ausgewählt für die Kopier- / Verschiebeoperation und / oder den Destruktor für die Objekt haben Nebenwirkungen.
Dies ermöglicht Implementierungen, "Konstruktion kopieren / verschieben" zu ermöglichen; Das Konstruieren eines Objekts mit etwas, das weder ein Kopierkonstruktor noch ein Move-Konstruktor ist, ist keine "Konstruktion kopieren / verschieben".
Da C
über einen benutzerdefinierten Destruktor verfügt, wird kein impliziter Move-Konstruktor generiert. Daher wählt die Überladungsauflösung den Vorlagenkonstruktor mit Args
abgeleitet als C
, was eine bessere Übereinstimmung als der implizite Kopierkonstruktor für rvalues ist. Der Compiler kann jedoch keine Aufrufe an diesen Konstruktor ausgeben, da er Nebeneffekte aufweist und weder ein Kopierkonstruktor noch ein Verschiebungskonstruktor ist.
Wenn der Vorlagenkonstruktor stattdessen
ist %Vor% Dann kann es nicht mit Args
= C
instanziiert werden, um einen Kopierkonstruktor zu erzeugen, da dies zu einer unendlichen Rekursion führen würde. Es gibt eine spezielle Regel im Standard, die solche Konstruktoren und Instanziierungen verbietet (§12.8 [class.copy] / p6):
Eine Deklaration eines Konstruktors für eine Klasse
X
ist schlecht formatiert, wenn seine Der erste Parameter ist vom Typ (optional cv-qualifiziert)X
und entweder Es gibt keine anderen Parameter oder alle anderen Parameter Standardargumente. Eine Elementfunktionsvorlage wird niemals instanziiert eine solche Konstruktorsignatur erzeugen.
In diesem Fall wäre also der einzige ausführbare Konstruktor der implizit definierte Kopierkonstruktor, und Aufrufe an diesen Konstruktor können weggelassen werden.
Wenn wir anstelle den benutzerdefinierten Destruktor aus C
entfernen und eine weitere Klasse hinzufügen, die bei% co_de verfolgt wird Der Destruktor von% wird stattdessen aufgerufen:
Wir sehen nur einen Aufruf von C
destructor, was darauf hinweist, dass nur ein D
-Objekt konstruiert ist. Hier wird der Bewegungskonstruktor von C
implizit generiert und durch die Überladungsauflösung ausgewählt, und Sie sehen, dass RVO erneut eingreift.
Tags und Links c++ templates rvalue-reference rvo universal-reference