c++language-lawyercomparison-operatorsc++23explicit-object-parameter

Defaulting comparison operator with explicit object parameter


In C++23 a class can have explicit object member functions (with the first parameter prefixed by this), including member comparison operators. Which of them a compiler can generate automatically after specifying =default?

My expectation was that any valid friend defaulted comparison operator will have similar valid explicit object member defaulted comparison operator (after replacing friend with this). But on practice with the current compilers it is not so.

First example:

struct A { 
    // ok everywhere
    friend bool operator ==(A, A) = default;
    // #1, ok in GCC, error in Clang
    bool operator ==(this A, A) = default;
};

Here friend operator definition is accepted by all compilers, but only GCC permits #1, and Clang complains:

<source>:5:22: error: defaulted member equality comparison operator must be const-qualified
    5 |     bool operator ==(this A, A) = default;
      |                      ^
      |                           const
<source>:5:10: error: invalid parameter type for defaulted equality comparison operator; found 'A', expected 'const A &'
    5 |     bool operator ==(this A, A) = default;

Online demo: https://gcc.godbolt.org/z/qjTavxWv6

In the second example:

struct A { 
    // fails everywhere
    //friend bool operator ==(const A, const A &) = default;
    // #2, ok in Clang, error in GCC
    bool operator ==(this const A, const A &) = default;
};

The counterpart for the invalid friend operator is accepted in Clang, while GCC denies it:

<source>:5:10: error: defaulted 'bool A::operator==(this A, const A&)' must have parameters of either type 'const A&' or 'A', not both
    5 |     bool operator ==(this const A, const A &) = default;

Online demo: https://gcc.godbolt.org/z/4r3q9fTrh

Which of explicitly defaulted operators (#1 or #2) are actually valid?


Solution

  • The wording in [class.compare.default] is pretty clear:

    A defaulted comparison operator function ([over.binary]) shall be a non-template function that

    • is a non-static member or friend of some class C,
    • is defined as defaulted in C or in a context where C is complete, and
    • either has two parameters of type const C& or two parameters of type C, where the implicit object parameter (if any) is considered to be the first parameter.

    So this is valid:

    struct A { 
        bool operator ==(this A, A) = default;
    };
    

    and this is not:

    struct A { 
        bool operator ==(this const A, const A &) = default;
    };