问题
Looking at Scott Meyer's Effective Modern C++ pages 200-201, the suggested simplified implementation of std::forward
could be (did see the proper implementation elsewhere):
template <typename T>
T&& forward(std::remove_reference_t<T>& param)
{ return static_cast<T&&>(param); }
And when accepting an rvalue Widget, it becomes:
Widget&& forward(Widget& param)
{ return static_cast<Widget&&>(param); }
Now, if you take that substituted code, and do:
struct Widget { };
Widget&& forward(Widget& param)
{ return static_cast<Widget&&>(param); }
template <typename T>
void G(T&& uref)
{ }
template <typename T>
void F(T&& uref)
{ G(forward(uref)); }
int main()
{
Widget x;
F(std::move(x));
}
What I can't wrap my head around, and didn't see a direct answer on SO yet, is: in forward
how does parameter Widget& param
manage to accept Widget&&
from F()? Normally gcc-5.0 would complain like so with non-template code:
error: invalid initialization of non-const reference of type ‘Widget&’ from an rvalue of type ‘std::remove_reference::type {aka Widget}’
(Question #27501400 nearly touches the topic, but not quite. It shows the standard as having both lvalue & and rvalue && versions.)
回答1:
"Named rvalue references are lvalues",
so example works fine as noted in a comment.
Nevertheless your code could be modified to
template <typename T>
void F(T && uref)
{
G(forward(move(uref)));
}
which is accepted by another overload (compare):
template<typename T>
T && forward(typename std::remove_reference<T>::type & t)
{
return static_cast<T &&>(t);
}
template<typename T>
T && forward(typename std::remove_reference<T>::type && t)
{
static_assert(!std::is_lvalue_reference<T>::value, "T is an lvalue reference");
return static_cast<T &&>(t);
}
The second overload will be used for rvalue. It works if T
is Widget
or Widget &&
and the assert fails for Widget &
.
来源:https://stackoverflow.com/questions/29041246/in-stdforward-how-does-it-accept-rvalue