C ++ 0x pokazuje przykład użycia std::forward
:
template<class T>
void foo(T&& arg)
{
bar(std::forward<T>(arg));
}
Kiedy std::forward
zawsze warto używać ?
Ponadto wymaga użycia &&
w deklaracji parametrów, czy jest ważny we wszystkich przypadkach? Myślałem, że musisz przekazać tymczasowe do funkcji, jeśli funkcja została &&
w niej zadeklarowana , więc czy można wywołać foo z dowolnym parametrem?
Na koniec, jeśli mam wywołanie funkcji, takie jak to:
template<int val, typename... Params>
void doSomething(Params... args) {
doSomethingElse<val, Params...>(args...);
}
Powinienem zamiast tego użyć:
template<int val, typename... Params>
void doSomething(Params&&... args) {
doSomethingElse<val, Params...>(std::forward<Params>(args)...);
}
Ponadto, jeśli dwukrotnie użyjesz parametrów w funkcji, tj. Przekażesz do dwóch funkcji w tym samym czasie, czy rozsądnie jest to zrobić std::forward
? Czy nie std::forward
przekonwertujesz tego samego na tymczasowy dwukrotnie, przenosząc pamięć i uniemożliwiając jej ponowne użycie? Czy poniższy kod byłby w porządku:
template<int val, typename... Params>
void doSomething(Params&&... args) {
doSomethingElse<val, Params...>(std::forward<Params>(args)...);
doSomethingWeird<val, Params...>(std::forward<Params>(args)...);
}
Jestem trochę zdezorientowany std::forward
i chętnie użyłbym jakiegoś wyjaśnienia.
źródło
Args...&& args
?Odpowiedź Kerreka jest bardzo przydatna, ale nie do końca odpowiada na pytanie z tytułu:
Aby na nie odpowiedzieć, należałoby najpierw wprowadzić pojęcie uniwersalnych odniesień . Scott Meyers nadał tę nazwę i obecnie są one często nazywane referencjami spedycyjnymi. Zasadniczo, gdy widzisz coś takiego:
pamiętaj, że
param
nie jest to odniesienie do wartości r (jak można by pokusić się z wnioskiem), ale odniesienie uniwersalne *. Odwołania uniwersalne charakteryzują się bardzo ograniczoną formą (tylkoT&&
, bez stałych lub podobnych kwalifikatorów) i dedukcją typu - typT
zostanie wydedukowany pof
wywołaniu. W skrócie, odwołania uniwersalne odpowiadają referencjom r-wartości, jeśli są zainicjowane rvalues, i referencjom l-wartości, jeśli są zainicjowane lvalues.Teraz stosunkowo łatwo odpowiedzieć na pierwotne pytanie - aplikuj
std::forward
do:Przykład dla pierwszego przypadku:
W powyższym kodzie nie chcemy
prop
mieć nieznanej wartości poother.set(..)
zakończeniu, więc nie ma tu żadnego przekazywania. Jednak dzwoniącbar
, przekazujemy dalej,prop
ponieważ już z nim skończyliśmy ibar
możemy z nim zrobić, co chce (np. Przenieść).Przykład dla drugiego przypadku:
Ten szablon funkcji powinien zostać przeniesiony
prop
do wartości zwracanej, jeśli jest to wartość r, i skopiować, jeśli jest to wartość l. W przypadku gdybyśmy pominęlistd::forward
na końcu, zawsze stworzylibyśmy kopię, która jest droższa, gdyprop
jest rvalue.* aby być w pełni precyzyjnym, uniwersalnym odniesieniem jest koncepcja wzięcia odniesienia r-wartości do niekwalifikowanego parametru szablonu cv.
źródło
Czy ten przykład pomaga? Usiłowałem znaleźć użyteczny, nieogólny przykład std :: forward, ale trafiłem na przykład konta bankowego, które przekazujemy jako argument do zdeponowania gotówki.
Więc jeśli mamy stałą wersję konta, powinniśmy się spodziewać, że po przekazaniu jej do naszego szablonu depozytu <> zostanie wywołana funkcja const; a to następnie zgłasza wyjątek (chodziło o to, że było to zablokowane konto!)
Jeśli mamy konto inne niż const, powinniśmy być w stanie je zmodyfikować.
Budować:
Oczekiwany wynik:
źródło