2013-10-03 21 views
18

Powiedzmy mam tę funkcję:Zachowanie C++ funkcji szablonu

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

Gdybym próbują nazwać z tym kodem:

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

kompilator będzie narzekać, że nie można konwertować X z lwartości odniesienie do referencji rvalue, które jest poprawne.

Teraz jeśli przekonwertować do funkcji f szablonu takich jak to:

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

to mogę nazwać go lwartością odniesienia:

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

Dlaczego tak jest? Dlaczego kompilator nie skarży się w tym przypadku?

Odpowiedz

8

Ponieważ jest odliczenie argumentu szablon, zawalenie odniesienie się dzieje. To właśnie Scott Meyers nazywa uniwersalnymi referencjami. Model U&& faktycznie stanie się int &. Jest ładny article and video o tym, jak to działa i jak można go użyć.

6

Dzieje się tak dlatego zawaleniem zasad referencyjnych dodanych w C++ 11

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

W szablonach zasady te są stosowane, ale nie w normalnych funkcji nie ma odniesienia zawaleniem zwykle w funkcji. Istnieją inne szczególne sytuacje, w których nastąpi zwijanie odwołań, podobnie jak w przypadku wystąpienia auto, decltype lub typedef (obejmujących deklaracje using), które wyjaśniają wyniki Twojej kompilacji. Zawinięcie referencyjne musiało zostać dodane w języku C++ 11, ponieważ w przeciwnym razie użycie odniesień takich jak A & & stałoby się błędami, ponieważ nie można odwoływać się do odwołania.

+2

Podczas gdy w przypadku "uniwersalnego odniesienia" występuje zwijanie odniesienia, prawdziwa magia dzieje się przed tym krokiem i występuje podczas dedukcji argumentu szablonu. Twoja notka o zwijaniu referencji nie działa w normalnej funkcji jest po prostu błędna; Zapadnięcie odniesienia może się zdarzyć wszędzie: 'using T = int &&; void foo (T & x); 'tutaj x jest' int & 'ze względu na zwijanie referencji – Simple

+0

@ Prosty wygląda jak twoje prawo, już wiedziałem, że decltypes i auto mogą mieć zwijanie referencji, nie wiedziałem, że typedef może spowodować to, I Zmienię moją odpowiedź – aaronman

10

Według § 8.3.3/6. Jest to referencyjna reguła zwijania.

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

Warto przykład ze standardowego projektu:

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

To jest trochę sprzeczne z intuicją ... –

+0

@VioletGiraffe witamy w świecie C++ –

+0

@jk .: I nie myślałem, że rozumiem większość tego świata! –

Powiązane problemy