When given code of the following structure
template <typename... Args> void foo(Args&&... args) { ... }   I've often seen library code use static_cast<Args&&> within the function for argument forwarding.  Typically, the justification for this is that using a static_cast avoids an unnecessary template instantiation.  
Given the language's reference collapsing and template deduction rules.  We get perfect forwarding with the static_cast<Args&&>, the proof for this claim is below (within error margins, which I am hoping an answer will enlighten)
&& && -> && (rule 1 above) & && -> & (rule 2 above)This is essentially getting foo() to forward the arguments to bar() in the example above.  This is the behavior you would get when using std::forward<Args> here as well.  
Question - why use std::forward in these contexts at all?  Does avoiding the extra instantiation justify breaking convention?  
Howard Hinnant's paper n2951 specified 6 constraints under which any implementation of std::forward should behave "correctly".  These were 
(1) and (2) were proven to work correctly with static_cast<Args&&> above.  (3) - (6) don't apply here because when functions are called in a deduced context, none of these can occur.
Note: I personally prefer to use std::forward, but the justification I have is purely that I prefer to stick to convention.  
The idiomatic use of std::forward is inside a templated function with an argument declared as a forwarding reference , where the argument is now lvalue , used to retrieve the original value category, that it was called with, and pass it on further down the call chain (perfect forwarding).
When t is a forwarding reference (a function argument that is declared as an rvalue reference to a cv-unqualified function template parameter), this overload forwards the argument to another function with the value category it had when passed to the calling function.
static_cast MAY take time at run-time. For example, if you convert int to float then work is required. Usually casting pointers does not require any run-time cost.
std::move is a cast. It takes any value as argument and returns that same value in the xvalue category. And a value of type T and category xvalue is denoted thus: T&& . The move operation itself is performed by one of the constructors of the object to which it moves.
Scott Meyers says that std::forward and std::move are mainly for convenience. He even states that std::forward can be used to perform the functionality of both std::forward and std::move.
 Some excerpts from "Effective Modern C++": 
Item 23:Understand std::move and std::forward
...
The story forstd::forwardis similar to that forstd::move, but whereasstd::moveunconditionally casts its argument to anrvalue,std::forwarddoes it only under certain conditions.std::forwardis a conditional cast. It casts to anrvalueonly if its argument was initialized with anrvalue.
...
Given that bothstd::moveandstd::forwardboil down to casts, the only difference being thatstd::movealways casts, whilestd::forwardonly sometimes does, you might ask whether we can dispense withstd::moveand just usestd::forwardeverywhere. From a purely technical perspective, the answer is yes:std::forwardcan do it all.std::moveisn’t necessary. Of course, neither function is really necessary, because we could write casts everywhere, but I hope we agree that that would be, well, yucky.
...std::move’s attractions are convenience, reduced likelihood of error, and greater clarity...
For those interested, comparison of std::forward<T> vs static_cast<T&&>  in assembly (without any optimization) when called with lvalue and rvalue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With