Overriding spaceship operator when parent class does not define spaceship operator for itself

Viewed 210

The following code is treated differently by the compilers:

#include <compare>

struct A;

struct I {
    virtual std::strong_ordering operator <=>(const A&) const { 
        return std::strong_ordering::equal; 
    }
};

struct A : I {
    virtual std::strong_ordering operator <=>(const A&) const = default;
};

Both GCC and MSVC accept it, but not Clang which returns the error:

warning: explicitly defaulted three-way comparison operator is implicitly deleted [-Wdefaulted-function-deleted]
    virtual std::strong_ordering operator <=>(const A&) const = default;
defaulted 'operator<=>' is implicitly deleted because there is no viable three-way comparison function for base class 'I'
error: deleted function 'operator<=>' cannot override a non-deleted function
    virtual std::strong_ordering operator <=>(const A&) const = default;

Demo: https://gcc.godbolt.org/z/WGrGTe89z

It seems that Clang is the only one right here, since I::operator <=>(const I&) const is not defined, so A::operator <=>(const A&) const must be implicitly deleted, and a deleted method cannot override a not deleted method from I. Are the other compilers also within their rights to accept the code?

1 Answers

The other compilers will also reject the code once you write something like A a; a < a;, which makes me think Clang is rejecting it prematurely. In [class.compare.default], the standard says:

A comparison operator function for class C that is defaulted on its first declaration and is not defined as deleted is implicitly defined when it is odr-used or needed for constant evaluation. Name lookups in the defaulted definition of a comparison operator function are performed from a context equivalent to its function-body. A definition of a comparison operator as defaulted that appears in a class shall be the first declaration of that function.

Since there is no expression resolving to A::operator<=>(const A&) in your example, no definition is needed and it should not be rejected, even if the function would always end up being deleted.

Related