Home > Enterprise >  std::forward not passing lvalue reference
std::forward not passing lvalue reference

Time:02-20

I am probably missing something basic here, but why don't I get a lvalue from std:forward bellow?

#include <iostream>
#include <utility>

template <typename T>
void f(const T& lhs) {
  std::cout << "lvalue" << "\n";
}

template <typename T>
void f(const T&& rhs) { // const, so as not to have a universal reference 
  std::cout << "rvalue" << "\n";
}

int main() {
  auto a = 3;
  f(a); // lvalue
  f(3); // rvalue
  f(std::forward<int>(a)); // rvalue ???
}

this compiles to

lvalue
rvalue
rvalue

I would expect the last result to be a lvalue.

CodePudding user response:

std::forward is a conditional std::move. Using it only makes sense inside of a template, where you choose whether to move or not depending on a template argument.

Like this:

template <typename T>
void foo(T &&value)
{
    f(std::forward<T>(value));
}

Here, T &&value is called a forwarding reference (as long T is deduced by the compiler, rather than specified manually), i.e. can accept both lvalues and rvalues.

If you pass an rvalue to this function, T is deduced to a non-reference, so T &&value remains an rvalue reference.

If you pass an lvalue, T is deduced to an lvalue reference, and T &&value becomes an lvalue reference (see reference collapsing rules).

To work with forwarding references, std::forward acts as an std::move if its template argument is not a reference, and does nothing if its template argument is an lvalue reference.

Since you passed a non-reference to it, you got a move, but again, it's not its intended use case.

CodePudding user response:

@HolyBlackCat's answer made me realise the problem and the solution. I'm not returning a reference from std:forward but an int so that's indeed a rvalue (since it doesn't have an address). With std::forward<int&> it's indeed correctly forwarding the lvalue reference. So this:

  f(a); // lvalue
  f(3); // rvalue
  f(std::move(a)); // rvalue
  f(std::forward<int>(a)); // rvalue !!!
  f(std::forward<int&>(a)); // lvalue

correctly returns

lvalue
rvalue
rvalue
rvalue
lvalue
  • Related