2012-12-31 4 views
5

Der Ausgang des folgenden Programms ...Vorlagenkonstruktor, der Vorrang vor normalem Konstruktor zum Kopieren und Verschieben hat?

#include <iostream> 

using namespace std; 

struct X 
{ 
    X(const X&)    { cout << "copy" << endl; } 
    X(X&&)     { cout << "move" << endl; } 

    template<class T> X(T&&) { cout << "tmpl" << endl; } 
}; 

int main() 
{ 
    X x1 = 42; 
    X x2(x1); 
} 

ist

tmpl 
tmpl 

Die gewünschte Ausgabe ist:

tmpl 
copy 

Warum das nicht der konkrete Copykonstruktor haben Vorrang vor Vorlagenkonstruktor?

Gibt es trotzdem eine Korrektur, damit die Überladungen des Kopier- und Verschiebungskonstruktors Vorrang vor dem Vorlagenkonstruktor haben?

+0

Hier ist die letzte Klasse zu dieser Frage: http://codereview.stackexchange.com/questions/20058/a-c11-any-class –

Antwort

2

Normale Überlast Auflösung Regeln gelten nach wie vor, wenn der Konstruktor der Auswahl - und ein Konstruktor eine nicht-const lvalue Referenz genommen wird (für die Vorlage Konstruktor nach Argument Abzug) ist eine bessere Übereinstimmung als ein Konstruktor eine const lvalue Referenz genommen wird.

Sie könnten natürlich einfach eine weitere Überladung hinzufügen, indem Sie eine nicht konstante lvalue-Referenz nehmen, d.

X(X&)    { cout << "copy" << endl; } 

aktualisieren: Andere Fälle, in denen die Vorlage Konstruktor ist eine bessere Übereinstimmung:

const X f() 
{ return X(); } 

struct Y : X 
{ Y() { } }; 

int main() 
{ 
    X x3(f()); // const-qualified rvalue 
    Y y; 
    X x4(y); // derived class 
} 
+0

Muss ich auch 'X (const X &&)' hinzufügen oder ist das unmöglich? Gibt es noch andere Fälle, in denen der Konstruktor move oder copy in der Abwesenheit des Vorlagenkonstruktors übereinstimmt? –

+0

@AndrewTomazosFathomlingCorps: SFINAE können Sie dort helfen, so dass Sie Ihre Funktion Signatur haben beide können * intakt * (Ich denke, das ist wichtig). Beispielsweise können Sie 'std :: enable_if' in der Funktionsvorlage verwenden, um nur die gewünschten Fälle zu aktivieren. – Nawaz

+0

Ja, wenn Sie einen konstanten Wert haben, z.B. aus 'const X f();' und 'X x3 (f())'. Dann gibt es den Fall, in dem der Initialisierer eine abgeleitete Klasse ist, die auch den Template-Konstruktor verwenden würde. – cmeerw

5

Nun, es ist wegen reference-collapsing.

Bei der Überlastungsauflösungsstufe, wenn die Funktionsschablone instanziert wird, wird T deduded X& sein, so T&& wird von der Funktionsschablone X& aufgrund referenz Kollabieren und die instanziierten Funktion wird genau (die X& && ist) Übereinstimmung und der Kopierkonstruktor erfordert eine Konvertierung von X& zu const X& (weshalb es nicht ausgewählt wird minderwertige Übereinstimmung).

Wenn Sie jedoch die const aus dem Kopierkonstruktor entfernen, wird der Kopierkonstruktor bevorzugt. Versuchen Sie Folgendes:

X(/*const*/ X&) { cout << "copy" << endl; } 

Output wie erwartet.

Oder alternativ, wenn Sie machen die Parameter in der Funktion Vorlage als const T& dann kopier Konstruktor aufgerufen wird (auch wenn es gleich bleibt!), Weil Referenz Kollabieren in Bild jetzt nicht kommen:

template<class T> X(const T &) { cout << "tmpl" << endl; } 

Output wird wieder erwartet.

3

Wenn Sie keinen anderen Konstruktor hinzufügen möchten (wie andere Antworten vorgeschlagen), können Sie SFINAE verwenden zu beschränken, um den Anruf, durch ersetzen der Vorlage Konstruktor durch diese:

template<class T 
    , typename std::enable_if<not std::is_same<X, typename std::decay<T>::type>::value, int>::type = 0 
> X(T&&) { cout << "tmpl " << endl; } 

, die einen dummy Standard templ beinhaltet gerade hinzufügen ate-Argument (eine bekannte Technik: http://www.boost.org/doc/libs/1_52_0/libs/utility/enable_if.html). Es sind keine zusätzlichen Header erforderlich.

Sie erhalten die gewünschte Ausgabe.

Ich habe diese Antwort von einem verwandten Problem: http://flamingdangerzone.com/cxx11/2012/06/05/is_related.html. All das sieht eher unelegant aus, scheint aber vorerst der einzige Ausweg zu sein. Ich möchte immer noch eine elegantere Lösung sehen.

Verwandte Themen