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 using std::move
you turn this to rvalue, you should remember it when you use a
next time.
b
the same as with a
- 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