Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why an Rvalue Reference is Turned into Lvalue Reference by a Universal Reference

I suppose when a universal reference parameter is matched with an rvalue reference argument, an rvalue reference argument is returned. However, my testing shows that the rvalue reference is turned into a lvalue reference by the universal reference function template. Why is it so?

#include <iostream>
#include <type_traits>
using namespace std;
template <typename T>
T f1(T&&t) {  //<-----this is a universal reference
  cout << "is_lvalue reference:" << is_lvalue_reference<T>::value << endl;
  cout << "is_rvalue reference:" << is_rvalue_reference<T>::value << endl;
  cout << "is_reference:"        << is_reference<T>::value        << endl;
  return t;
}
void f2(int&& t) {
  cout << "f2 is_lvalue reference:" << is_lvalue_reference<decltype(t)>::value << endl;
  cout << "f2 is_rvalue reference:" << is_rvalue_reference<decltype(t)>::value << endl;
  cout << "f2 is_reference:" << is_reference<decltype(t)>::value << endl;
  f1(t);

}

int main()
{
  f2(5);
  return 0;
}

In both GCC and VC++2010, this is the result:

f2 is_lvalue reference:0
f2 is_rvalue reference:1
f2 is_reference:1
is_lvalue reference:1
is_rvalue reference:0
is_reference:1

In other words, the parameter t in f2 was an rvalue reference, but when passed to f1, the parameter became a lvalue reference. Shouldn't it retain the rvalue-ness in f1?

like image 301
JavaMan Avatar asked Dec 24 '22 22:12

JavaMan


1 Answers

The reason is that named rvalue references are treated as lvalues.

You should use std::move inside f2 when passing t to f1 to retain rvalueness:

void f2(int&& t) {
    f1(std::move(t));
}

Here you can find a good explanation.

like image 190
Edgar Rokjān Avatar answered Apr 28 '23 14:04

Edgar Rokjān