As far as I know, in C++11, universal reference should always be used with std::forward
, but I am not sure of what kind of problem can occur if std::forward
is not used.
template <T>
void f(T&& x);
{
// What if x is used without std::forward<T>(x) ?
}
Could you provide some illustrations of problems that could occur in this situation ?
There is no such rule to always use
std::forward
with universal references. On the contrary, it can be dangerous to usestd::forward
all over the place in functions with universal references. Take a look at the following example:If you call this function with
make_pair(std::string{"foobar"})
, the result is counter-intuitive, because you move from the same object twice.Update: Here is another example to show, that it really makes sense to use universal references without perfect forwarding:
std::forward
for range or for action.Let's say
f
is called like this:If the body of
f
performs some kind of operation onx
and there are two overloads for
foo
without using
std::forward
, asx
is an lvalue the following overload is calledwhich might cost you a potential optimization.
Using
makes sure the correct overload of
foo
is selected.You should not forward a variable more than once.
Things with a name are lvalues. That means that in the function body,
t
is an lvalue. It doesn't matter if the universal reference ends up as an lvalue reference or as an rvalue reference. If it's named, it's an lvalue.If you thus pass that argument along directly, you will be passing an lvalue.
In a situation where you want to just pass along an opaque argument to another function, you want to pass it exactly as-is. If it was an lvalue, you want to pass it as an lvalue; if it was an rvalue you want to pass an rvalue. As explained, passing it directly passes it as an lvalue always.
forward
does the magic needed to pass it as the right kind of value,Code that always passes an lvalue will likely suffer from a performance perspective but I would say that you can ignore that when thinking about this particular issue. There is a more pressing concern for not always passing an lvalue: while copying some types may be expensive, some other types cannot be copied at all, like
std::unique_ptr
. For those types preserving rvalueness when forwarding is not a matter of performance but of getting your code to even compile.