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

Time:01-20

#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 doesn't pick it up? How to properly explain it?

CodePudding user response:

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.

CodePudding user response:

The && in the declaration of

void foo(A&& a)

only has an effect to the outside (caller) of the function, but (almost) not inside the function. To the caller, it says "I only accept rvalues".

Inside the function, there is almost no difference between && and &, in particular, a is an lvalue. For this reason, bar(A& a) is the only viable candidate.

  •  Tags:  
  • Related