Why does std::forward converts lvalue and rvalue to rvalue reference?

c++, c++11, lvalue, rvalue

Solution

why `std::forward` converts both as rvalue reference

It shouldn't. According to the rule of forwarding reference, when an lvalue is passed to `add`, the template type argument `Element` will be deduced as `SomeClass&`. Then `std::forward<SomeClass&>(element)` will be invoked, and the instantiation of `std::forward` would be

// before reference collapsing
constexpr SomeClass& &&
forward(SomeClass& __t) noexcept
{ return static_cast<SomeClass& &&>(__t); }

and

// after reference collapsing
constexpr SomeClass&
forward(SomeClass& __t) noexcept
{ return static_cast<SomeClass&>(__t); }

So for the 1st case, `std::forward` will return an lvalue. An lvalue-reference returned from function is an lvalue.

BTW, for the 2nd case, the templare argument `Element` will be deduced as `SomeClass`, then you can do the same inference as above, at last the instantiation of `std::forward` would be

constexpr SomeClass&&
forward(SomeClass& __t) noexcept
{ return static_cast<SomeClass&&>(__t); }

An rvalue-reference returned from funtion is an rvalue.

The result you got seems weird, for the 1st case, `std::vector::push_back(const T&)` should be invoked. (I tried a mcve, here)

Problem

I suppose I am confused with `std::forward`. My function which uses `std::forward` is following, but it is much simplified and modified to make explanation easily. ``` // This is an example code to explain my question simply. template <typename Element> void add(Element&& element) { static std::vector vec; vec.push_back(std::forward<Element>(element)); } ``` I tried two case with the function above; Case 1 lvalue argument and Case 2 rvalue argument. Case 1: lvalue argument ``` auto some_class = SomeClass(); add(some_class); ``` Case 2: rvalue argument ``` add(SomeClass()); ``` In debugger both cases passes the same following parts, `std::forward` part and `std::vector` part. `std::forward` part: ``` template<typename _Tp> constexpr _Tp&& forward(typename std::remove_reference<_Tp>::type& __t) noexcept { return static_cast<_Tp&&>(__t); } ``` `std::vector` part: ``` #if __cplusplus >= 201103L void push_back(value_type&& __x) { emplace_back(std::move(__x)); } ``` It seems `std::forward` part converts both cases to rvalue reference, `&&`, because it uses `static_cast<_Tp&&>`. And `std::vector` is treated both elements as rvalue reference because it uses `std::move()`. I have expected augment of Case 1 is lvalue because it has its own name and Case 2 is rvalue because it does not have its own name. I also have expected `std::forward` converts Case 1 to lvalue reference and Case 2 to rvalue reference. Are my understandings of lvalue, rvalue and `std::forward` correct? If so, why `std::forward` converts both as rvalue reference, `&&`. If I made a mistake, I am sorry for taking your time.

Original source