2015-06-29 17 views
5

Staram się zrozumieć, co dokładnie dzieje się podczas przekazywania referencji do funkcji funkcji jako uniwersalnej referencji (jaki typ jest wydedukowywany). Załóżmy, że mamy foo funkcję, która pobiera param jako uniwersalnego odniesienia:Przekazywanie odwołania do funkcji jako uniwersalnego odniesienia

template<typename T> 
void foo(T&& param) 
{ 
    std::cout << __PRETTY_FUNCTION__ << std::endl; 
} 

A potem zróbmy następujące:

void(&f)(int) = someFunction; 
foo(f); 

Rezultatem będzie:

void foo(T&&) [with T = void (&)int]

Jest to całkowicie zrozumiałe: przechodzimy do l-wartości naszej funkcji foo, więc wyprowadzony typ jest nieważny (&) int, a typem parametru będzie "void (& & &) int", który w ramach odwołania do reguł zwijania stanie się nieważny (&) int. Param będzie tylko lwartym odniesieniem do funkcji.

Ale kiedy należy wykonać następujące czynności:

void(&f)(int) = someFunction; 
foo(std::move(f)); 

foo wypisze:

void foo(T&&) [with T = void (&)int]

która jest dokładnie taka sama jak poprzednio! Co tu się dzieje? Dlaczego wynik jest taki sam jak przy przejściu do lwartości? Spodziewalibyśmy się, że skoro przechodzimy rvalue do foo, to dedukowany typ powinien być T = void (int), a parametr powinien zostać unieważniony (& &) int. Dzieje się tak zawsze w przypadku wszystkich innych "normalnych" typów (takich jak klasy, typy pierwotne itd.). Dlaczego jest inaczej w przypadku odniesień do funkcji?

+0

Nah. 'param' ma nazwę, z definicji jest l-wartością. –

+3

@KerrekSB Przepraszamy, ale to źle - http: // stackoverflow.com/questions/7016777/what-is-an-rvalue-reference-to-function-type –

+0

@rubix_addict: Mój zły, dzięki! Oddalony. Byłem po oświadczeniu, które jest częścią odpowiedzi, ale nie zrozumiałem tego. –

Odpowiedz

6

A std::move jest gloryfikowanym typem referencyjnym ravenue static_cast. Norma mówi, że rzucanie do wartości odniesienia r względem typu funkcji nadal daje lwartość. Za [expr.static.cast]/P1:

Wynikiem ekspresji static_cast<T>(v) jest wynikiem konwersji ekspresję v wpisać T. Jeśli T jest typem odniesienia lwartości lub referencją wartości r względem typu funkcji, wynikiem jest l-wartość;

Jeśli chodzi o kategorię wartość wezwania std::move() funkcji, która zwraca odwołanie rvalue wyznaczającą wynik konwersji, możemy również zobaczyć z [expr.call]/p10, że wywołanie funkcji jest lwartością jeśli jej Zwraca typ jest odniesienie RValue funkcjonować typ:

połączenie funkcja lwartością jeśli typ rezultacie typ odniesienia lwartość lub referencja RValue funkcjonować typu An xvalue jeśli typ rezultacie odwołanie do wartości rwartości do typu obiektu i wartość dodana rwise.

+0

Bardzo ładna odpowiedź. W intuicyjnym sensie odniesienie do typu funkcji będzie traktowane nieco inaczej; funkcje nie mają stanu i dlatego nie można ich przesunąć, a odwołanie do funkcji nie może zmienić tej funkcji. odniesienie do typów funkcji skutecznie zawsze zachowują się jak const &. Mimo to nadal mnie zastanawia, dlaczego konieczne jest wyraźne stwierdzenie, że te konwersje występują. Jakie dziwne, bezsensowne przykłady kodu można wymyślić w przypadku braku tej reguły? –

+0

Ah, miło! Wydaje się to nieco skomplikowane, gdy istnieje wiele sposobów uzyskiwania tego, co byłoby funkcją xvalue, mówiąc w ten sposób, że w rzeczywistości daje ona zamiast niej funkcję l-value, ale właśnie nią jest. :) – hvd

Powiązane problemy