In C 11 and later, one can decorate the member function with &
, const&
, oe &&
(or other combinations).
If one has several overloads, and at least one is specified like this, the others must follow the same convention.
Pre C 11 style:
struct A {
void f() const {} // #1
void f() {} // #2
};
C 11 and later:
struct {
void f() const& {} // #3
void f() & {} // #4
// void f() && {} // if necessary
};
Until today, I though that #4
was equivalent to #2
, but today I found a counter example:
struct A {
void f() & {}
// void f() && {} // commented for testing purposes, see below
}
struct B {
void f() {}
}
...
A{}.f(); // compile error: argument discards qualifiers
B{}.f(); // ok
https://godbolt.org/z/qTv6hMs6e
So, what is the deal? An undecorated (non-const) member function written in the old style is equivalent to both its &&
or &
version depending on the context (at the calling point)?
Is the below code the correct interpretation?
struct B {
void f() {... some body...}
}
...is the same as this?
struct B {
void f() & {... some body...}
void f() && {... some (same) body...}
}
CodePudding user response:
The qualifiers have the exact same meaning as if they were the qualifiers on the hypothetical implicit object parameter which is passed the object expression of the member access expression.
So, #4 can not be called on a prvalue, because a non-const
lvalue reference can not bind to a prvalue, explaining why A{}.f();
doesn't work. (A{}
is a prvalue)
The old style without reference qualifier is the odd one. It behaves in overload resolution as if the implicit object parameter was an lvalue reference (const
or not depending on that qualifier), but in contrast to normal function parameters it is allowed to bind to rvalues anyway for the purpose of overload resolution.
So to replicate the old style unqualified behavior, you need to specify both the &
-qualified overload and the &&
-qualified overload (at least if the function is not also const
-qualified). (There are likely some corner cases where the two qualified member functions are not 100% equivalent to one unqualified one though. I guess a simple example would be trying to take the address &B::f
.)