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