Skip to content

Intermediate Gotchas

The Rvalue Reference That Is an Lvalue

the parameter type is not the expression category

void inspect(const std::string&) { std::cout << "lvalue\n"; }
void inspect(std::string&&) { std::cout << "rvalue\n"; }

void send(std::string&& message) { inspect(message); }

int main() { send("hello"); }

Run it. Which overload sees message?

Answer
lvalue

Giving a variable an rvalue-reference type did not make its name an rvalue.

Why

message has type std::string&&, but every named variable expression is an lvalue. Overload resolution therefore selects the const std::string& overload. This is not forwarding-reference deduction; the same named-expression rule applies to every rvalue-reference parameter. GCC emits no warning under -Wall -Wextra.

The fix

Cast only when this function is done with the object:

void send(std::string&& message) { inspect(std::move(message)); }

Takeaway: a named rvalue-reference parameter is an lvalue until you explicitly move it.

Try it: g++ -std=c++17 main.cpp -o demo && ./demo

Open in Compiler Explorer ↗ Quiz this entry