The forwarding reference is defined as follows: "Forwarding references are a special kind of references that preserve the value category of a function argument, making it possible to forward it by means of std::forward." (https://en.cppreference.com/w/cpp/language/reference)
By "preserve the value category of a function argument", I understand that the name of an argument variable whose type is a forwarding reference, has the same value category as in the function's invocation. For example:
template<typename T>
void wrapper(T&& forwarded_argument) {
some_function(forwarded_argument);
}
wrapper(5);
wrapper(my_int);
Here, the expression 5
in the first invocation is a prvalue, so as I understand it, the expression forwarded_argument
(just the name of the variable) within some_function(forwarded_argument);
, should also be a prvalue.
In the second invocation, the name my_int
is an lvalue, so I would expect the expression forwarded_argument
within some_function(forwarded_argument);
to be an lvalue.
This would make writing this line as std::forward<T>(forwarded_argument)
unnecessary, since in both cases, the correct overload of some_function
would be called anyway, based on what I pass to wrapper
.
I also think I don't fully understand what std::forward
actually does. Here's a simplified implementation I found (The implementation of std::forward):
template <class T>
inline T&& forward(typename std::remove_reference<T>::type& t) noexcept {
return static_cast<T&&>(t);
}
template <class T>
inline T&& forward(typename std::remove_reference<T>::type&& t) noexcept {
static_assert(!std::is_lvalue_reference<T>::value, "Can not forward an rvalue as an lvalue.");
return static_cast<T&&>(t);
}
As cppreference states (https://en.cppreference.com/w/cpp/language/value_category), a cast expression to an rvalue reference to an object type, such as static_cast<char&&>(x)
, is an xvalue. I don't see any mention of the value category of x
, so I assume the value category of the whole cast expression is the same regardless. And the value category of a function call expression, whose return type is an rvalue reference to an object, is an xvalue. From this, it appears that no matter what I pass to std::forward
, the value category of a call to std::forward
will always end up being an xvalue.
Where is the mistake here? The conclusions in both parts of the question (about forwarding references and about std::forward
) seem incorrect, judging by the way forwarding is usually done.