2013-10-03 12 views
18

Lassen Sie uns sagen, ich habe diese Funktion:Verhalten von C++ Template-Funktion

bool f(int&& one, int&& two) { } 

Wenn ich versuche, es mit diesem Code zu nennen:

int x = 4; 
f(x, 5); 

der Compiler wird sich beschweren, dass es nicht x von L-Wert umwandeln kann Verweis auf Rvalue-Referenz, die korrekt ist.

Nun, wenn ich f in eine Template-Funktion wie folgt konvertieren:

template <class T, class U> 
bool f(T&& one, U&& two) { } 

dann kann ich es mit einem L-Wert-Referenz nennen:

int x = 5; 
f(x, 5); 

Warum ist es so? Warum beschweren sich die Compiler in diesem Fall nicht?

Antwort

8

Da es ein Abzug Template-Argument ist, geschieht Referenz Kollabieren. Es ist das, was Scott Meyers Universalreferenzen nennt. Die U&& wird tatsächlich int & werden. Es gibt eine nette article and video über wie es funktioniert und wie es genutzt werden könnte.

6

Dies geschieht, weil die Referenz kollabieren Regeln in C++ hinzugefügt 11

A& & becomes A& 
A& && becomes A& 
A&& & becomes A& 
A&& && becomes A&& 

In Vorlagen diese Regeln angewandt werden, aber nicht in einer normalen Funktion gibt es keinen Hinweis normalerweise in Funktion kollabieren. Es gibt einige andere spezifische Situationen, in denen Referenzzusammenbrüche auftreten, wie in Anwesenheit von auto, decltype oder typedef (das beinhaltet using Deklarationen). Das erklärt die Ergebnisse Ihrer Kompilierung. Das Referenz-Kollabieren musste in C++ 11 hinzugefügt werden, da andernfalls die Verwendung von Referenzen wie A & & zu Fehlern würde, da Sie keinen Verweis auf eine Referenz haben können.

+2

Während das Referenz-Kollabieren im Fall einer "universellen Referenz" auftritt, tritt die wahre Magie vor diesem Schritt auf und tritt während der Template-Argumentableitung auf. Ihre Anmerkung zum Kollabieren von Referenzen, die nicht in einer normalen Funktion funktionieren, ist einfach falsch. Das kollabierende Referenzieren kann überall passieren: 'using T = int &&; void foo (T & x); 'hier x ist ein' int & 'aufgrund der kollabierenden Referenz. – Simple

+0

@Simple sieht aus wie rechts, ich wusste bereits, dass decltypes und auto Referenz kollabieren konnte, wusste nicht, dass ein typedef es verursachen könnte, ich Ich werde meine Antwort ändern – aaronman

10

Nach § 8.3.3/6. Es ist die Referenz kollabierenden Regel.

template <class T> void func(T&&) // Accepts rvalue or lvalue 
void func(T&&)      // Accepts rvalue only 
void func(T&)      // Accepts lvalue only 

Worth Beispiel von Standard-Entwurf:

int i; 
typedef int& LRI; 
typedef int&& RRI; 

LRI& r1 = i;   // r1 has the type int& 
const LRI& r2 = i;  // r2 has the type int& 
const LRI&& r3 = i; // r3 has the type int& 

RRI& r4 = i;   // r4 has the type int& 
RRI&& r5 = 5;   // r5 has the type int&& 

decltype(r2)& r6 = i; // r6 has the type int& 
decltype(r2)&& r7 = i; // r7 has the type int& 
+3

Dies ist eine Art kontraintuitiv ... –

+0

@VioletGiraffe willkommen in C++ 's Welt –

+0

@jk .: Und da dachte ich, ich verstehe die meisten dieser Welt! –