Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can I invoke == with a defaulted <=> but not a user-provided one?

#include <compare>

struct A
{
    int n;
    auto operator <=>(const A&) const noexcept = default;
};

struct B
{
    int n;
    auto operator <=>(const B& rhs) const noexcept
    {
        return n <=> rhs.n;
    }
};

int main()
{
    A{} == A{}; // ok
    B{} == B{}; // error: invalid operands to binary expression
}

compiled with clang-10 as clang -std=c++20 -stdlib=libc++ main.cpp

Why does A{} == A{} work but not B{} == B{}?

like image 418
xmllmx Avatar asked Apr 05 '20 08:04

xmllmx


People also ask

How do you call a default constructor in C++?

base a declares a variable a of type base and calls its default constructor (assuming it's not a builtin type). base a(); declares a function a that takes no parameters and returns type base .

What is the purpose of a default constructor?

A default constructor in Java is created by the compiler itself when the programmer doesn't create any constructor. The purpose of the default constructor is to initialize the attributes of the object with their default values.

Is it always necessary to provide a default constructor for a class Why or why not?

It's not mandatory to define default constructor, but if you are writing Hibernate persistent class, JPA entities, or using the Spring framework to manage object creation and wiring dependencies, you need to be a bit careful.

What are the default functions provided in C++?

In C++, the compiler automatically generates the default constructor, copy constructor, copy-assignment operator, and destructor for a type if it does not declare its own. These functions are known as the special member functions, and they are what make simple user-defined types in C++ behave like structures do in C.


1 Answers

In the original design of the spaceship operator, == is allowed to call <=>, but this is later disallowed due to efficiency concerns (<=> is generally an inefficient way to implement ==). operator<=>() = default is still defined to implicitly define operator==, which correctly calls == instead of <=> on members, for convenience. So what you want is this:

struct A {
    int n;
    auto operator<=>(const A& rhs) const noexcept = default;
};

// ^^^ basically expands to vvv

struct B {
    int n;
    bool operator==(const B& rhs) const noexcept
    {
        return n == rhs.n;
    }
    auto operator<=>(const B& rhs) const noexcept
    {
        return n <=> rhs.n;
    }
};

Note that you can independently default operator== while still providing a user-defined operator<=>:

struct B {
    int n;
    // note: return type for defaulted equality comparison operator
    //       must be 'bool', not 'auto'
    bool operator==(const B& rhs) const noexcept = default;
    auto operator<=>(const B& rhs) const noexcept
    {
        return n <=> rhs.n;
    }
};
like image 120
L. F. Avatar answered Sep 21 '22 08:09

L. F.