2016-09-30 1 views
1
#include <iostream> 

template <typename T> 
class test 
{ 
public: 
    test(T&& t) 
    { 
    } 
}; 

template <typename T> 
void succeed(T&& t) 
{ 
} 

int main() 
{ 
    int i = 1; 
    test<int> t(i); // failed to compile 
    succeed(i);  // OK 
    return 0; 
} 

Fehler von GCC 5.2: main.cpp: In Funktion 'int main()': main.cpp: 20: 18: Fehler: kann nicht binden, 'int' lvalue zu 'Int & &' Test t (i); ^ main.cpp: 7: 5: Anmerkung: Initialisieren Argument 1 von 'Test :: Test (T & &) [mit T = int]' Test (T & & t) ^ ~~~rvalue Referenz in Klassenschablone vs Funktionsschablone

Könnte jemand erklären, warum die Klassenvorlage nicht kompilieren kann, aber die Funktionsvorlage OK ist? Danke.

+0

Es wäre einfacher zu erklären, wenn wir tatsächlich die Fehler kennen, die Sie bekommen. Wenn Sie Fragen zu Buildfehlern stellen, sollten Sie immer die vollständige Fehlerausgabe in den Hauptteil der Frage einfügen. Bitte bearbeiten Sie Ihre Frage, um diese zu berücksichtigen. Bitte geben Sie auch den verwendeten Compiler an und welche Version davon. –

Antwort

3

Ihre Verwechslung beruht wahrscheinlich auf Ihrer Annahme, dass in beiden Fällen Tint ist. Aus diesem Grund vermuten Sie, dass diese beiden Fälle ähnlich sind. In Wirklichkeit sind sie nicht. In der Klassenversion geben Sie manuell an, was T ist. Sie sagen dem Compiler explizit, dass Tint ist. Der Konstruktorparametertyp T && wird in diesem Fall int &&, der nicht an einen regulären Lvalue gebunden werden kann. Daher der Fehler.

In der Funktionsversion sagen Sie dem Compiler nicht, was T ist, aber stattdessen erwarten Sie, dass der Compiler daraus abgeleitet. In Situationen wie Ihrer ist die Sprache absichtlich darauf ausgelegt, T als int & abzuleiten (Hinweis: nicht als int, sondern eher als int &). Sobald T als int & abgeleitet wird, führen die so genannten "reference collapsing" rules zu Funktionsparameter Typ werden int & - eine gewöhnliche lvalue Verweis. Dieser Parameter kann erfolgreich an das Lvalue-Argument i gebunden werden.

Das erklärt den Unterschied, den Sie beobachten.

Aus Gründen der Versuch, im letzteren Fall können Sie Template-Argument Abzug unterdrücken und die Template-Argument explizit angeben

succeed<int>(i); 

Das gewaltsam T als int geben wird und wie in der zum gleichen Fehler führen Klassenversion aus dem gleichen Grund.

Ebenso können Sie „simulieren“ Verhalten der Funktion für die Klasse durch das Template-Argument als int & Angabe

test<int &> t(i); 

die gleiche „Referenz kollabiert“ Regeln Konstruktor Aufruf erfolgreich zu kompilieren machen.

4

In succeed, T&& t ist eine Weiterleitungsreferenz, kein rvalue Verweis. Aber in test ist es eine rvalue-Referenz.

Eine Weiterleitungsreferenz findet nur statt, wenn der Parameter T&& lautet, und T ist ein Vorlagenparameter dieser Funktion. In Ihrem Code T ist ein Vorlagenparameter der einschließenden Klasse, so dass es nicht als eine Weiterleitungsreferenz zählt.

Eine Weiterleitungsreferenz kann sowohl an L-Werte als auch an R-Werte gebunden sein.

Während der Erstellung von C++ 11 wurde vorgeschlagen, eine andere Syntax für die Weiterleitung von Referenzen als Rvalue-Referenzen zu verwenden (anstelle von T&& t für beide); Das Komitee entschied sich jedoch schließlich für das aktuelle Verhalten.

Für eine detailliertere Beschreibung der Parameter Abzug Vorlage, einschließlich einer genaueren Spezifikation, wenn T&& wird eine Weiterleitung Referenz, see here - für den Begriff „Forwarding reference“ suchen die besonderen Regeln für die Weiterleitung Referenzen zu finden.

Verwandte Themen