2014-03-04 7 views
7

Dies ist ein Followup von function template does not recognize lvalueVerständnis Vorlage Argument Abzug mit rvalue/L-Wert

Fangen wir mit dem folgenden Code spielen:

#include <iostream> 
template <class T> 
void func(T&&) { 
    std::cout<<"in rvalue\n"; 
} 

template <class T> 
void func(const T&) { 
    std::cout<<"in lvalue\n"; 
} 

int main() 
{ 
    double n=3; 
    func<double>(n); 
    func(n); 
} 

Er druckt:

in lvalue 
in rvalue 

Ich verstehe nicht, was passiert im zweiten Anruf. Wie der Compiler den Template-Parameter auflösen? Warum gibt es keine Zweideutigkeit?

+5

Sie können 14.8.2 im Standard konsultieren. Template Argument Abzug ist ein etwas komplexes Thema. Der Punkt ist, dass die "beste Übereinstimmung" gewählt wird, und dass "T" als Referenztyp abgeleitet werden kann. –

+0

"etwas komplexes Thema"! Ich stimme vollkommen zu. Übrigens, gibt es eine Möglichkeit, g ++/clang ++ zu fragen, worum es hier geht? – hivert

+0

Diese unschuldige kleine Untersektion nimmt 15 Seiten ein und entwickelt eine ganz neue mathematische Notation: -S Aber letztlich "macht was du denkst", du musst nur Template-Parameter als ehrliche Typen im Kontext einer Funktionssignatur annehmen. –

Antwort

13

Wenn Sie func<double>(n) sagen, gibt es keinen Argumentabzug, da Sie das Argument angeben, und die Auswahl liegt zwischen func(double &&) und . Ersteres ist nicht praktikabel, weil eine rvalue-Referenz nicht an einen lvalue binden kann (nämlich n).

Nur func(n) führt Argumentabzug durch. Dies ist ein komplexes Thema, aber auf den Punkt gebracht, haben Sie diese zwei mögliche Kandidaten:

T = double &: func(T &&)  --> func(double &)   (first overload) 
T = double:  func(const T &) --> func(const double &) (second overload) 

Die erste Überlastung ist strikt besser, weil es ein erfordert weniger Umwandlung des Arguments Wert (nämlich double-const double).

Die magische Zutat ist die "reference collapsing", was bedeutet, dass eine L-Wert T && Referenz sein kann, wenn T selbst ein Referenztyp (specificaly wird double & &&double &, und das erlaubt es der erste Abzug vorhanden ist).

+0

Ich denke, Herb Sutters Artikel [Warum nicht Spezialfunktionsvorlagen spezialisieren?] (Http://www.gotw.ca/publications/mill17.htm) hilft auch, dieses Verhalten zu verstehen. – piwi

+3

@piwi Abgesehen davon, dass es seit Einführung der rvalue-Referenzen hoffnungslos veraltet ist. @Kerrek macht es nicht wirklich deutlich: Wenn Template-Argumentableitung stattfindet, ist das '&&' in 'func (T &&') ** nicht ** eine rvalue-Referenz, sondern eine universelle Referenz, die beides werden kann eine R-Wert-Referenz (wenn das Argument ein R-Wert ist) oder eine L-Wert-Referenz (wenn das Argument ein L-Wert ist). Scott Meyer erklärt dies gut in http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers; das ist der Artikel, den ich für diese spezielle Frage empfehlen würde. –

+0

@JamesKanze Ich bin mir der doppelten Bedeutung von '&&' bewusst, abhängig vom Kontext, aber Sie haben Recht, dass Herb Sutters Artikel dies nicht behandelt; Ich fand es jedoch nützlich, Auflösungsregeln zu verstehen, wenn man Vorlagen und Überladungen "mischt". Danke für den Link! – piwi