I found the following code cann’t be compiled before c++20:
#include <iostream>
using namespace std;
struct B;
struct C;
struct A {
A(int v) : val(v) {}
bool operator==(A &a) { return val == a.val; }
private:
int val;
friend struct B;
};
struct B : private A {
B(int v) : A(v) {};
bool operator==(A &a) { return this->val == a.val; }
bool operator==(B &a) { return this->val == a.val; }
};
int main() {
A a(1);
B b(2);
cout << (a == a) << endl;
cout << (a == b) << endl;
cout << (b == a) << endl;
cout << (b == b) << endl;
}
my g++ version:
g++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
compile in c++17
g++ main.cpp -std=c++17
main.cpp: In function ‘int main()’:
main.cpp:24:17: error: ‘A’ is an inaccessible base of ‘B’
24 | cout << (a == b) << endl;
| ^
compile in c++20:
g++ main.cpp -std=c++20
./a.out
1
0
0
1
It seems that after c++20, if compiler finds a == b
is invalid, it will try to replace a == b
with b == a
instead. Was my guess correct?
6
It seems that after c++20, if compiler finds
a == b
is invalid, it will try to replacea == b
withb == a
instead. Was my guess correct?
Almost. A synthesized candidate is added to the candidate set of overloads where the order of the two parameters is reversed, so that part is correct:
[over.match.oper]
/3.4.4
For the equality operators, the rewritten candidates also include a synthesized candidate, with the order of the two parameters reversed, for each non-rewritten candidate for the expression
y == x
.
But that means that even if a == b
would be valid (using A::operator==
), it’d still use B::operator==
since that requires fewer conversions. It’s the same if you’d have an overloaded function like this:
void foo(const A&); // would be used by `a`
void foo(const B&); // would be used by `b`
So, with the inheritance made public
…
struct B;
struct A {
A(int v) : val(v) {}
bool operator==(const A&) const noexcept;
private:
int val;
friend struct B;
};
struct B : public A { // made public
B(int v) : A(v) {}
bool operator==(const A&) const noexcept;
bool operator==(const B&) const noexcept;
};
… different overloads will be called in C++17 and C++20:
cout << (a == b) << endl; // C++17: A::operator==(const A&)
// C++20: B::operator==(const A&)
Demo
0