2

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.)

Community
  • 1
  • 1
JasonM
  • 21
  • 3
  • 6
    Named rvalue references are lvalues; real rvalues are accepted by a separate overload. – T.C. Mar 13 '15 at 20:30
  • @T.C. That is precisely the aspect I was overlooking, thanks. – JasonM Mar 13 '15 at 20:40
  • 1
    If it has a name, it's an lvalue. So `uref` is an lvalue. – Jonathan Wakely Mar 13 '15 at 21:13
  • @JasonM I have actually emailed Scott about the exact same issue, as I thought it is a mistake. He basically left out the rvalue overload since he couldn't think of any usage case for it. I recently asked about this [here](http://stackoverflow.com/q/29859696/3093378) – vsoftco Apr 26 '15 at 17:39

1 Answers1

0

"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 &.

Lukáš Bednařík
  • 2,578
  • 2
  • 15
  • 30