Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::forward not passing lvalue reference

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.

like image 789
Marinos K Avatar asked Mar 23 '26 10:03

Marinos K


1 Answers

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.

like image 151
HolyBlackCat Avatar answered Mar 26 '26 01:03

HolyBlackCat