问题
I have the following code:
#include <iostream>
using namespace std;
void test(int& a) {
cout << "lvalue." << endl;
}
void test(int&& a) {
cout << "rvalue" << endl;
}
int main(int argc, char *argv[]) {
int a = 1;
int&& b = 2;
test(a);
test(1);
test(std::move(a));
test(b);
}
which outputs:
lvalue.
rvalue
lvalue.
lvalue.
std::move()
and int&&
are rvalue references, I wonder why test(std::move(a))
and test(b)
output lvalue
? Is it related with signature matching and function overloading?
回答1:
The output should be:
lvalue.
rvalue
rvalue
lvalue.
There is a very important distinction to be made between expressions which are rvalues and expressions whose type is an rvalue reference. The type of b
is an rvalue reference to int
, but the expression b
is an lvalue; it is a variable, you can take its address. This is why the final line of output is lvalue
rather than rvalue
. In order to change it to an rvalue, you should call std::move
on it:
test(std::move(b));
回答2:
You can read this article, which explains it very well Universal References in C++11. Also it worth mentioning that now these references called forwarding references.
In your case you have
void test(int& a); // lvalue reference overload
void test(int&& a); // rvalue reference overload
Second case allows you to implement move semantics or perfect forwarding inside the function. Though first one also allows it, only you need to use std::move
which will turn its value to rvalue.
test(a);
test(1);
test(std::move(a));
test(b);
a
has a name, so applying move semantics to it tacitly would be dangerously confusing and error-prone because the thing from which we just moved, is still accessible on subsequent lines of code.1
has no name, you can take the address of it, so it is an rvalue.std::move(a)
by usingstd::move
you turn this to rvalue, you should remember it when you usea
next time.b
the same as witha
- it has a name, you can take the address of it.
Some examples of lvalues and rvalues:
// lvalues:
//
int i = 42;
i = 43; // ok, i is an lvalue
int* p = &i; // ok, i is an lvalue
int& foo();
foo() = 42; // ok, foo() is an lvalue
int* p1 = &foo(); // ok, foo() is an lvalue
// rvalues:
//
int foobar();
int j = 0;
j = foobar(); // ok, foobar() is an rvalue
int* p2 = &foobar(); // error, cannot take the address of an rvalue
j = 42; // ok, 42 is an rvalue
来源:https://stackoverflow.com/questions/34784755/c11-lvalue-rvalue-and-stdmove