I found the following code can'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.
Is my guess correct?
It seems that after c++20, if compiler finds
a == bis invalid, it will try to replacea == bwithb == ainstead. 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
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