L'operatore di uguaglianza non viene definito per un'implementazione personalizzata dell'operatore di astronave in C++ 20




c++20 spaceship-operator (2)

Sto riscontrando uno strano comportamento con il nuovo operatore dell'astronave <=> in C ++ 20. Sto usando Visual Studio 2019 compilatore con /std:c++latest .

Questo codice viene compilato correttamente, come previsto:

#include <compare>

struct X
{
    int Dummy = 0;
    auto operator<=>(const X&) const = default; // Default implementation
};

int main()
{
    X a, b;

    a == b; // OK!

    return 0;
}

Tuttavia, se cambio X in questo:

struct X
{
    int Dummy = 0;
    auto operator<=>(const X& other) const
    {
        return Dummy <=> other.Dummy;
    }
};

Ottengo il seguente errore del compilatore:

error C2676: binary '==': 'X' does not define this operator or a conversion to a type acceptable to the predefined operator

Ho provato anche questo su clang e ho un comportamento simile.

Gradirei qualche spiegazione sul perché l'implementazione predefinita genera correttamente operator== , ma quella personalizzata no.


Durante la standardizzazione di questa funzionalità, è stato deciso che l'uguaglianza e l'ordinamento dovrebbero essere logicamente separati. Pertanto, l'uso del test di uguaglianza ( == e != ) Non invocherà mai l' operator<=> . Tuttavia, è stato ancora considerato utile essere in grado di predefinire entrambi con una singola dichiarazione. Quindi, se l' operator<=> predefinito operator<=> , è stato deciso che intendevi anche l' operator== predefinito operator== (a meno che non lo definissi in seguito o lo avessi definito in precedenza).

Per quanto riguarda il motivo per cui questa decisione è stata presa , il ragionamento di base va così. Considera std::string . L'ordinamento di due stringhe è lessicografico; ogni carattere ha il suo valore intero rispetto a ciascun carattere nell'altra stringa. La prima disuguaglianza si traduce nel risultato dell'ordine.

Tuttavia, il test di uguaglianza delle stringhe ha un corto circuito. Se le due stringhe non hanno la stessa lunghezza, non ha senso fare un confronto saggio; non sono uguali. Quindi, se qualcuno sta facendo dei test sull'uguaglianza, non vorrai farlo a lungo se riesci a cortocircuitare.

Si scopre che molti tipi che richiedono un ordinamento definito dall'utente offriranno anche alcuni meccanismi di cortocircuito per i test di uguaglianza. Per impedire alle persone di implementare solo l' operator<=> e di gettare via le potenziali prestazioni, forziamo efficacemente tutti a fare entrambe le cose.


Le altre risposte spiegano molto bene perché la lingua è così. Volevo solo aggiungere che nel caso in cui non fosse ovvio, è ovviamente possibile avere un operator<=> fornito dall'utente operator<=> con un operator== predefinito operator== . Devi solo scrivere esplicitamente l' operator== predefinito operator== :

struct X
{
    int Dummy = 0;
    auto operator<=>(const X& other) const
    {
        return Dummy <=> other.Dummy;
    }
    bool operator==(const X& other) const = default;
};






spaceship-operator