Why can't a function with an rvalue parameter be forwarded without explicit type cast?

#include <iostream>

using namespace std;

struct A{};

void bar(A& a) {
    cout << "in bar A&";
}

void bar(A&& a) {
    cout << "in bar A&&";
}

void foo(A&& a) {
    bar(a);
}

int main()
{
    foo(A());
    return 0;
}

This program prints the following:

in bar A&

Instead of the following:

in bar A&&

Regarding the the forwarding problem, void bar(A&& a) is a better choice than void bar(A& a) in this code. But why doesn't the compiler pick it up? How to properly explain it?


when writing

void foo(A&& a) {
    bar(a);
}

you say that foo receives a rvalue, but as you do not move it to bar, foo remains owner of the a thus the only possible bar() call is a A&

If you want bar to take ownership, then move it (actually a cast to rvalue...):

void foo(A&& a) {
    bar(std::move(a));
}

should do what you expect...

EDIT:

Follow up the question why is a not a rvalue when calling bar?

Actually, you do not expect it to be a rvalue; imagine the code was:

void foo(A&& a) {
    bar(a);
    bar2(a);
}

When looking at this, one would expect a to remain "valid" event if there was a call to bar() right before (this is the usual behaviour in a function regardless a was received as a rvalue or not).

while writing:

void foo(A&& a) {
    bar(std::move(a));
    // here you suspect already something goes wrong
    bar2(a); // what is supposed to be 'a' if it was moved?
}

In this case you would expect the call to bar2() to be wrong (and would likely not do what you expect)

So here was about why it is a good that the bar(&) is called.

For the "why", the reason is that named rvalue references are treated as lvalues.