2010-06-01 7 views
26

Sind Variadic-Konstruktoren dazu gedacht, die implizit erzeugten zu verbergen, d. H. Den Standardkonstruktor und den Kopierkonstruktor?Sollen variadic Konstruktoren die implizit erzeugten Konstrukte verbergen?

struct Foo 
{ 
    template<typename... Args> Foo(Args&&... x) 
    { 
     std::cout << "inside the variadic constructor\n"; 
    } 
}; 

int main() 
{ 
    Foo a; 
    Foo b(a); 
} 

Irgendwie erwartete ich dies nach this answer Lesen nichts zu drucken, aber er druckt inside the variadic constructor zweimal auf g ++ 4.5.0 :(Ist dieses Verhalten korrekt


Es kommt auch ohne variadische Vorlagen?:

struct Foo 
{ 
    Foo() 
    { 
     std::cout << "inside the nullary constructor\n"; 
    } 

    template<typename A> Foo(A&& x) 
    { 
     std::cout << "inside the unary constructor\n"; 
    } 
}; 

int main() 
{ 
    Foo a; 
    Foo b(a); 
} 

Wiederum sind beide Linien gedruckt.

+1

Ich habe gerade einen schnellen Test auf gcc45 ausgeführt, und ein regulärer, nicht-variadischer Template-Konstruktor verhindert die Erstellung eines Compiler-generierten Standardkonstruktors. Mein Verdacht ist, dass sich die Regeln in C++ 0x geändert haben. –

+2

@Dennis: Ich wäre _really_ überrascht, wenn C++ 0x Regeln ändern würde, die mit C++ 0x eingeführt werden. ':)' – sbi

+0

@Dennis Also ist die verknüpfte Antwort gefälscht? Es besagt, dass "ein Vorlagenkonstruktor oder ein Zuweisungsoperator den vom Compiler erzeugten nicht unterdrücken wird". – fredoverflow

Antwort

19

Die Deklaration des implizit deklarierten Kopierkonstruktors wird nicht unterdrückt. Es wird einfach nicht wegen der Regeln der Überladungsauflösung aufgerufen. Der implizit deklarierte Kopierkonstruktor hat das Format Foo(const Foo&). Der wichtige Teil davon ist, dass es eine konstante Referenz braucht. Ihre Konstruktorvorlage verwendet eine nicht konstante Referenz.

a ist nicht const, daher wird die nicht-const von einem Benutzer deklarierte Konstruktorvorlage dem implizit deklarierten Kopierkonstruktor vorgezogen. die implizit deklarierte Kopie Konstruktor aufzurufen, können Sie a const machen:

const Foo a; 
Foo b(a); 

oder Sie static_cast verwenden können, eine konstante Referenz auf a zu erhalten:

Foo a; 
Foo b(static_cast<const Foo&>(a)); 

Die Überladungsauflösung Regeln, die diese beschreiben sind gefunden meist in §13.3.3.2/3 der C++ 0x FCD. Dieses besondere Szenario mit einer Kombination aus L-Wert und rvalue Referenzen, ist eine Art von den verschiedenen Beispielen auf Seite 303.


A variadische Konstruktor Vorlage des implizit deklarierte Standardkonstruktors wird unterdrücken, weil eine variadische Konstruktor Vorlage Benutzer -declared und die implizit deklariert Standardkonstruktor wird nur zur Verfügung gestellt, wenn es keine Benutzer deklarierte Konstruktoren (C++ 0x FCD §12.1/5) sind:

wenn es X, kein Benutzer deklarierten Konstruktor für die Klasse ist ein Konstruktor ohne Parameter wird implizit als Standard deklariert.

A variadische Konstruktor Vorlage wird die implizit deklariert Copykonstruktor nicht unterdrücken, da nur ein nicht-Template kann ein Konstruktor Copykonstruktor (§12.8/2, 3, 8 und C++ 0x FCD) sein:

eine nicht-Template-Konstruktor für Klasse X ist eine Kopie Konstruktor, wenn seine erste Parameter vom Typ ist X&, const X&, volatile X& oder const volatile X& und entweder gibt es keine weiteren Parameter oder auch alle anderen Parameter Standardargumente haben.

Eine Nicht-Template-Konstruktor für Klasse X ist ein Schritt Konstruktor, wenn seine erste Parameter vom Typ ist X&&, const X&&, volatile X&& oder const volatile X&& und entweder gibt es keine weiteren Parameter oder auch alle anderen Parameter Standardargumente haben.

Wenn die Klassendefinition keinen Kopierkonstruktor explizit deklariert und es keinen von Benutzern deklarierten Move-Konstruktor gibt, wird ein Kopierkonstruktor implizit als Standard deklariert.

+0

@James "Ein Vorlagenkonstruktor [...] ist nie ein Kopierkonstruktor" -> also g ++ 4.5.0 ist fehlerhaft und die zweite Zeile sollte nichts drucken? Und mit FCD meinst du n3090? – fredoverflow

+0

@Fred: Der FCD ist n3092; Ich musste die Zitate aktualisieren, weil ich aus irgendeinem Grund n3035 geöffnet hatte und es gibt einige Änderungen in n3092 ... Entschuldigung. –

+0

@James Es passiert auch mit nicht-variadischen Vorlagen, ich habe meine Frage aktualisiert! – fredoverflow