Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 429
3l4x Avatar asked Jun 21 '19 15:06

3l4x


People also ask

Are rvalue references Lvalues?

lvalue references are marked with one ampersand (&). And an rvalue reference is a reference that binds to an rvalue. rvalue references are marked with two ampersands (&&). Note that there is one exception: there can be lvalue const reference binding to an rvalue.

How do rvalue references work?

An rvalue reference is formed by placing an && after some type. An rvalue reference behaves just like an lvalue reference except that it can bind to a temporary (an rvalue), whereas you can not bind a (non const) lvalue reference to an rvalue.

What are Lvalues and Rvalues?

An lvalue (locator value) represents an object that occupies some identifiable location in memory (i.e. has an address). rvalues are defined by exclusion. Every expression is either an lvalue or an rvalue, so, an rvalue is an expression that does not represent an object occupying some identifiable location in memory.

What is rvalue C++?

An rvalue is an expression that is not an lvalue. Examples of rvalues include literals, the results of most operators, and function calls that return nonreferences. An rvalue does not necessarily have any storage associated with it.


1 Answers

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
like image 65
NathanOliver Avatar answered Nov 15 '22 19:11

NathanOliver