Reputation: 103
So I wanted to practice the usage of std::forward
and created a Test
class with 2 constructors. 1 with T&
and the other with T&&
as overload. T&
prints lvalue, and T&&
prints rvalue so I know which one of the constructors is being used. I create 2 instances of class on stack and to my surprise both of which are using the T&&
overload.
#include <iostream>
#include <type_traits>
#include <utility>
template <class T> auto forward(T &&t) {
if constexpr (std::is_lvalue_reference<T>::value) {
return t;
}
return std::move(t);
}
template <class T> class Test {
public:
Test(T &) { std::cout << "lvalue" << std::endl; };
Test(T &&) { std::cout << "rvalue" << std::endl; };
};
int main() {
int x = 5;
Test<int> a(forward(3));
Test<int> b(forward(x));
return 0;
}
I tried using the original std::forward
function and implementing it but both times it printed rvalue x2. What am I doing wrong?
Upvotes: 10
Views: 251
Reputation: 180630
Your problem stems from the return type of forward
. You use auto
as the return type which will not deduce a reference for you. That means when you do return, no matter which branch it returns from, you return by value which means you have a prvalue.
What you need is decltype(auto)
so you return an rvalue or lvalue reference, depending on the return statement. Using
template <class T> decltype(auto) forward(T &&t) {
if constexpr (std::is_lvalue_reference<T>::value)
return t;
else
return std::move(t);
}
gives you the output:
rvalue
lvalue
Upvotes: 14