The name of a variable used as an expression is always an lvalue, even if the variable's type is an rvalue reference. (Though decltype
has some additional rules, not just looking at the expression's value category.) This is an intentional choice of the C++ language, because otherwise it would be too easy to accidentally move from a variable.
For example:
void debug_str_val(std::string var_name, std::string value);
void MyClass::set_name(const std::string& name)
{
debug_str_val("name", name);
m_name = name;
}
void MyClass::set_name(std::string&& name)
{
debug_str_val("name", name); // *
m_name = std::move(name);
}
On the line marked with a *
, name
is treated as an lvalue, so debug_str_val
gets a copy of the value. (It maybe could use const std::string&
parameters instead, but it doesn't.) If name
were treated as an rvalue, the debug_str_val
would be moved from, and then an unpredictable value would be assigned to m_name
.
Once an object has a name, it could be used more than once, even if that name is an rvalue reference. So C++ uses it as an lvalue by default and lets the programmer say when they want it to be used as an rvalue, using std::move
, or sometimes std::forward
, or an explicit cast to rvalue reference type.