Why is my code printing rvalue 2 times instead of rvalue & lvalue?
Asked Answered
W

1

10

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?

Witcher answered 21/6, 2019 at 15:34 Comment(1)
auto is never a reference.Salbu
D
14

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
Darryl answered 21/6, 2019 at 15:43 Comment(4)
Isn't there such a thing as an auto&, or am I making up silliness?Mcvay
@Chipster There is, but that will always return an lvalue reference, which would not be what you want in a forwarding function.Darryl
@Witcher You'e welcome. Good first effort BTW. Generic code and forwarding can be pretty tough to get right.Darryl
@NathanOliver, even for compilers. ;)Salbu

© 2022 - 2024 — McMap. All rights reserved.