2016-11-17 17 views
5

Jak stwierdzono w cplusplus.com, std::forward ma dwa podpisy:Dlaczego istnieją dwa sygnatury std :: forward?

template <class T> T&& forward (typename remove_reference<T>::type& arg) noexcept; 
template <class T> T&& forward (typename remove_reference<T>::type&& arg) noexcept; 

Typowe zastosowanie std::forward jest zachowanie rvalueness przechodząc argumenty do innych funkcji. Zilustrujmy to na przykładzie:

void overloaded(int &) { std::cout << "lvalue"; } 
void overloaded(int &&) { std::cout << "rvalue"; } 

template <typename T> 
void fwd(T && t) 
{ 
    overloaded(std::forward<T>(t)); 
} 

Kiedy wzywamy fwd(0), T wnioskuje do int (t ma typ int &&). Następnie dzwonimy pod numer std::forward<int>(t). Wynikiem tego połączenia jest wyrażenie typu int &&, dlatego wybrano drugą wersję funkcji overloaded, a program wypisze "rvalue" na standardowe wyjście.

Kiedy wzywamy fwd(i) (gdzie jest jakiś int zmienna), T wnioskuje, do int& (t ma typ int &). Następnie dzwonimy pod numer std::forward<int&>(t). Wynikiem tego połączenia (po zastosowaniu referencyjnych reguł zwijania) jest wyrażenie typu int &, dlatego wybrano pierwszą wersję funkcji overloaded, a program wypisze "lwartość" na standardowe wyjście.

W obu przypadkach używamy pierwszego przeciążenia z std::forward (ten pobierający typename remove_reference<T>::type& arg). Dzieje się tak, ponieważ nawet jeśli typ t jest int &&, wiąże on referencję lwartościową (ponieważ zmienna nazwana typu "odniesienie r wartości do czegoś" jest sama w sobie lwartością, a wartości l nie mogą wiązać się z odniesieniem do wartości r).

Pytanie 1:

Co to jest drugi przeciążenie std::forward za? Czy możesz wymyślić jakiś praktyczny przykład, który używa przeciążenia pobierając arg przez referencję rwartości?

Pytanie 2:

cplusplus.com mówi:

Both signatures return the same as:

static_cast<decltype(arg)&&>(arg) 

Mam problem z tym, że jestem pewien, że to jest złe. Kiedy próbujemy zwrócić to od pierwszego przeciążenia std::forward, otrzymujemy błąd kompilacji.

Kiedy fwd nazywa się int rvalue, wywołuje pierwszy przeciążenie std::forward z T = int. Następnie decltype(arg) stanie się int&, więczapadnie się do static_cast<int&>(arg). Ale typ zwracany jest int && i otrzymujemy błąd kompilacji:

cannot bind ‘std::remove_reference<int>::type {aka int}’ lvalue to ‘int&&’ 

Oba przeciążone wersje std::forward powinien powrócić static_cast<T&&>(arg). Czy mam rację?

Czy uważasz, że cytat z cplusplus.com jest błędem?

+0

Zobacz http://stackoverflow.com/questions/38344332/why-does-stdforward-hole-two-overloads dla odpowiedzi na pierwsze pytanie. – TartanLlama

+0

@TartanLlama To, że jeden ma garść 'const' i' const_cast' skrócone przez tho. – Yakk

+4

'cplusplus.com' to NIE' cppreference'. 'cppreference.com' to' cppreference'. Znać różnicę. – Nawaz

Odpowiedz

1
class Foo {}; 

auto f = [](){ return Foo{}; }; 
auto g = []()->Foo&{ static Foo x; return x; }; 

template<class T> 
std::false_type is_rvalue(T&) { return {}; } 
template<class T> 
std::true_type is_rvalue(T&&) { return {}; } 

template<class T, class F> 
auto test(F&& f) { 
    return is_rvalue(std::forward<T>(f())); 
} 

int main() { 
    std::cout << test<Foo>(f) << "," << test<Foo&>(g) << "\n"; 
} 

To jest trochę wymyślne; ale wyobraź sobie, gdzie masz fabrykę, która może wytworzyć Foo lub Foo& zależnie od pewnych nieistotnych szczegółów, ale chcesz ją przekazać w oparciu o drugi typ T na T&&. Wiesz, że jeśli T nie jest odniesieniem, nie będzie produkować Foo, ale jeśli T jest odniesieniem, może.

Powiązane problemy