The most common usage of std::forward
is to, well, perfect forward a forwarding (universal) reference, like
template<typename T>
void f(T&& param)
{
g(std::forward<T>(param)); // perfect forward to g
}
Here param
is an lvalue
, and std::forward
ends up casting it to a rvalue or lvalue, depending on what the argument that bounded to it was.
Looking at the definition of std::forward
from cppreference.com I see that there is also a rvalue
overload
template< class T >
T&& forward( typename std::remove_reference<T>::type&& t );
Can anyone give me any reason why the rvalue
overload? I cannot see any use case. If you want to pass a rvalue to a function, you can just pass it as is, no need to apply std::forward
on it.
This is different from std::move
, where I see why one wants also a rvalue
overload: you may deal with generic code in which you don't know what you're being passed and you want unconditional support for move semantics, see e.g. Why does std::move take a universal reference?.
EDIT To clarify the question, I'm asking why overload (2) from here is necessary, and a use case for it.
This answer is for answering comment by @vsoftco
In short:
Because without a rvalue specialization the following code would not compile
however I can't resist to type more so here's also the not succint version of the answer.
Long version:
You need to move
v
because the classLibrary
has no constructor accepting lvalue to it, but only a rvalue reference. Without perfect forwarding we would end up in a undesired behaviour:with move semantics we make sure that move constructor is used IF POSSIBLE. In the above example if we remove
std::forward
the code will not compile.So what is actually doing
forward
? moving the element without our consensus? Nope!It is just creating a copy of the vector and moving it. How can we be sure about that? Simply try to access the element.
if you instead move that element
So that overload is needed to make possible a implicit conversion that is still safe, but not possible without the overload.
Infact the following code will just not compile:
Real use case:
You may argue that forwarding arguments may create useless copies and hence hide a possible performance hit, yes, that's actually true, but consider real use cases:
Code was taken from my framework (line 80): Infectorpp 2
In that case arguments are forwarded from a function call.
SmartPointers::resolve
's returned values are correctly moved regardless of the fact that constructor ofImpl
accept rvalue or lvalue (so no compile errors and those get moved anyway).Basically you can use
std::foward
in any case in wich you want to make code simpler and more readable but you have to keep in mind 2 pointsIf used with care is a powerfull tool.
I stared at this question before, read Howard Hinnant's link, couldn't fully grok it after an hour of thinking. Now I was looking and got the answer in five minutes. (Edit: got the answer is too generous, as Hinnant's link had the answer. I meant that I understood, and was able to explain it in a simpler way, which hopefully someone will find helpful).
Basically, this allows you to be generic in certain kinds of situations depending on the typed that's passed in. Consider this code:
This code prints "move". What's interesting is that if I remove the
std::forward
, it prints copy. This, for me, is hard to wrap my mind around, but let's accept it and move on. (Edit: I suppose this happens because get will return a lvalue reference to an rvalue. Such an entity decays into an lvalue, but std::forward will cast it into an rvalue, just as in the common use of forward. Still feels unintuitive though).Now, let's imagine another class:
Suppose in the code in
main
,h
was an instance of Hello2. Now, we no longer need std::forward, because the call tostd::move(h).get()
returns an rvalue. However, suppose the code is generic:Now when we call
func
, we'd like it to work properly with bothHello
andHello2
, i.e. we'd like to trigger a move. That only happens for an rvalue ofHello
if we include the outerstd::forward
, so we need it. But... We got to the punchline. When we pass an rvalue ofHello2
to this function, the rvalue overload of get() will already return an rvalue double, sostd::forward
is actually accepting an rvalue. So if it didn't, you wouldn't be able to write fully generic code as above.Damn.
Ok since @vsoftco asked for concise use case here's a refined version (using his idea of having "my_forward" to actually see wich overload gets called).
I interpret "use case" by providing a code sample that without prvalue not compile or behave differently (regardless of that would be really usefull or not).
We have 2 overloads for
std::forward
And we have 4 possible use cases
Use case 1
Use case 2
Use case 3
Use case 4
Here's a resume
Note that if we do not use forward
you get:
As you see, if you use only one of the two
forward
overloads, you basically cause to not compile 2 out of 4 cases, while if you do not useforward
at all you would get to compile only 3 out of 4 cases.