0

I have a function that has a lvalue reference as argument, and I found that I can also pass a rvalue reference to it. However, when I passing the result of std::move to the function, I get an error which tells me that I cannot bind non-const lvalue reference to an rvalue.

#include <iostream>
#include <string>

template<typename T>
void foo(T& a) { }

struct A {
    std::string s;
};

int main(int argc,char** argv) {
    A a{"a"};
    A&& ra = std::move(a); 
    foo(ra);            // OK
    foo(std::move(a));  // Error
    return 0;
}

I was thinking that std::move also returns a rvalue reference. What is the difference between using an intermediate rvalue reference as argument and directly using the result of std::move as argument?

Nolazuck
  • 81
  • 4
  • `ra` is an **lvalue expression** when used in `foo(ra);` – Jason Jun 12 '22 at 14:56
  • 2
    [This question](https://stackoverflow.com/questions/27603035/c-11-rvalue-reference-variables) covers a little of the territory. Somewhat counterintuitively, `ra` is _still_ an lvalue--after all, it has a name, and it's valid to put it on the left hand side of an `=`. – Nathan Pierson Jun 12 '22 at 14:57
  • In the [duplicate](https://stackoverflow.com/questions/71968902/forwarding-reference-and-argument-deduction/71968945#71968945) it is explained that `ra` is the name of a variable and is an lvalue expression. – Jason Jun 12 '22 at 15:00
  • 2
    The first thing to understand that [expressions can't have reference types](http://eel.is/c++draft/expr#type-1). When a function returns `T &&`, the actual result of the call has type `T`, and "xvalue" value category. (Similarly, returning `T &` gives an lvalue, and returning non-reference gives a prvalue). But standalone rvalue references (unlike ones returned from a function) don't impose the "xvalue" value category. Like all other variables, they are lvalues. (Or rather, expressions consisting of a variable name are lvalues.) – HolyBlackCat Jun 12 '22 at 15:00

1 Answers1

0

ra is a named variable. As such, it is an lvalue and can be bound to an lvalue reference.

std::move(a) returns a A&&, but that returned value is a prvalue. lvalue references cannot bind to prvalues.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402