Consider this code:
#include <iostream>
using namespace std;
struct A {
void f() { cout << "A::f" << endl; }
void f() const { cout << "A::f const" << endl; }
};
struct B {
void f() & { cout << "B::f &" << endl; }
void f() const & { cout << "B::f const &" << endl; }
};
A getA() { return A{}; }
B getB() { return B{}; }
int main() {
getA().f();
getB().f();
}
which prints
A::f
B::f const &
For B
, the const overload gets selected, not the non-const one. I guess this means that specifying a lvalue ref qualifier for *this is different from not specifying anything at all. Why is that? Does the "implicit this argument" change type and the const overload now becomes a better candidate in overload resolution?
In this case:
struct A {
void f() { cout << "A::f" << endl; }
void f() const { cout << "A::f const" << endl; }
};
getA().f();
Both overloads are viable for f
, but the non-const one is preferred because it requires no conversion.
But in this case:
struct B {
void f() & { cout << "B::f &" << endl; }
void f() const & { cout << "B::f const &" << endl; }
};
getB().f();
The first overload requires this
to be an lvalue. But in getB().f()
, the result of getB()
is a prvalue, which can't bind to a non-const lvalue. So this overload is not viable and not selected.
The second overload however requires this
to be a const lvalue, which a prvalue can bind to: this overload is viable and selected by the compiler.
For reference, the sentence that totally misled me is in [over.match.funcs]
, §13.3.1/4 of N3337:
- For non-static member functions, the type of the implicit object parameter is
— “lvalue reference to cv X” for functions declared without a ref-qualifier or with the & ref-qualifier
— “rvalue reference to cv X” for functions declared with the && ref-qualifier
(emphasis mine).
So I was getting kind of crazy about why there was a difference in the output. Without or with a &
ref qualifier should be the same according to here, right?
Well, the reason is an additional rule sneaked in afterwards in §13.3.1/5
For non-static member functions declared without a ref-qualifier, an additional rule applies:
— even if the implicit object parameter is not const-qualified, an rvalue can be bound to the parameter as long as in all other respects the argument can be converted to the type of the implicit object parameter.
Which basically triggers the non-const rvalue to non-const lvalue conversion and makes all the difference in the example above. D'uh.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With