Consider this code:
template<typename T>
void foo(T&& param){ //In this case && is called universal reference
std:string tmp = std::forward<string>(param);
}
My question is if universal reference type can be deduced why do I still need to call forward ?
Why without forwarding tmp's correct c'tor won't be called even if T's type was deduced.
My second question is about reference collapsing rules:
A& &&
becomesA&
A&& &&
becomesA&&
so according this rules and taking in account universal reference why std::forward signature can't be as follows:
template<class T>
T&& forward(T&& arg){
return static_cast<T&&>(arg);
}
According to the rules from above if T
's type is rvalue reference it will collapse to rvalue reference , if T's type is lvalue reference it will collapse to lvalue reference.
So why std::forward
have two different signatures one for lvalue reference and one for rvalue reference am I missing something ?
Because as soon as you give a name to the parameter
param
it is an lvalue, even if the function was called with an rvalue, so it wouldn't be forwarded as an rvalue unless you useforward<T>
Because
param
is an lvalue. To restore the value category of the argument passed tofoo
you need to cast it back tostring&
orstring&&
which means you need to know the typeT
was deduced as, and useforward
to do the cast.It was changed by http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3143.html
There is lots of background info in http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3143.html and http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2951.html
The problem with your suggested version is that if you say
forward<string>
then the parameterT
is not deduced so doesn't function as a forwarding reference, which means thatT&&
can't bind to an lvalue, and it needs to be able to bind to an lvalue in order forforward<string>(param)
to work, becauseparam
is an lvalue there.