Named rvalue references are lvalues

Which overload of f in this C++ code snippet would be executed given its argument? A or B?

1
2
3
4
void f(int&) { ... } // A
void f(int&&) { ... } // B
 
f(123);

If you guessed B, you would indeed be correct. If you've learned about rvalue references it's most likely you have a basic understanding of what rvalues are; the expression 123 should fit that description, as it is a prvalue, or a pure rvalue. Now what if the argument to f was written like this?

1
2
3
4
5
void f(int&) { ... } // A
void f(int&&) { ... } // B
 
int&& x = 123;
f(x);

If you guessed B, you would be incorrect because A is the overload that gets called. This is a common misunderstanding of rvalue references -- and I've recognized it enough as a source of confusion for new-comers (and sometimes the experienced) that I thought I would briefly write about it.

So why is x an lvalue? In terms of syntax it might look like it should match the parameter for overload B, but looks can be deceiving! A simple rule for figuring out if an expression is an lvalue is if it is a name (the standard uses the term "identity of an object"). In the first snippet, the expression 123 does not have a name: it's an initialization of an int "object" with the value 123. However in the second snippet, we can see that x is a name for a variable of type int&&; x is the name of a reference to an int "object". So following the "has a name" rule, the expression x is an lvalue.

Tags: c++, beginner, c++11