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.