Asking for a friend:
Why does std::forward
in the following code cast the parameter c
to an rvalue ?
template <typename T>
void f (T& c) {
using value_type = typename std::remove_reference_t<T>;
std::vector<value_type> v;
// debugger reveals: push_back( T&& value ) is called here
v.push_back(std::forward<T>(c));
}
Note that c
is not a universal/forwarding reference here. I am aware of the fact that this function would most probably be of more use if it actually was, but curious all the same.
std::forward<T>(c)
is equivalent to static_cast<T&&>(c)
.
If T&&
is a forwarding reference then this allows an lvalue to be forwarded as an lvalue because T
will be deduced as an lvalue reference type and T&&
will be the same lvalue reference type by the reference-collapsing rules. In your situation, T&&
is not a forwarding reference, so this doesn't work.
To understand this situation, you have to understand why forwarding references work. Given a definition like
template <typename T>
void foo(T&& t) {}
when you write something like
some_type some_object;
foo(some_object);
template deduction deduces T
to be some_type&
. Now the parameter t
has the type some_type& &&
. Since you can't have references to references, reference collapsing rules are applied and some_type& &&
is collapsed to some_type&
.
If, instead, you write something like
some_type some_object;
foo(std::move(some_object));
template deduction deduces T
to be some_type
. Now the parameter t
has the type some_type&&
. That's a perfectly valid type, so no reference collapsing is done.
Now we get to std::forward
. All std::forward<U>
does is cast its parameter to U&&
. If U
is some_type
, as in the second case above, the parameter is cast to some_type&&
. It remains an rvalue-reference. If U
is some_type&
, as in the first case above, reference collapsing is performed again, and some_type& &&
becomes some_type&
. So std::forward
returns an lvalue-reference.
So the ultimate answer to your original question is that the return type of std::forward
only depends on the type passed as std::forward
's template parameter. Since T
in your case will always be deduced as a non-reference type, std::forward
will always return an rvalue-reference.
Well, the definition of std::forward<T>(x)
is to cast x
to type T&&
. If you pass a non-reference as argument you'll get an rvalue reference T&&
back. Since your T
cannot be a reference type (you cannot have a reference to a reference), it must be a non-reference type.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.