Napotykam dziwne zachowanie z nowym operatorem statku kosmicznego <=>
w C ++ 20. Korzystam z kompilatora Visual Studio 2019 z /std:c++latest
.
Ten kod kompiluje się zgodnie z oczekiwaniami:
#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;
}
Jeśli jednak zmienię X na to:
struct X
{
int Dummy = 0;
auto operator<=>(const X& other) const
{
return Dummy <=> other.Dummy;
}
};
Otrzymuję następujący błąd kompilatora:
error C2676: binary '==': 'X' does not define this operator or a conversion to a type acceptable to the predefined operator
Próbowałem tego również na clang i mam podobne zachowanie.
Byłbym wdzięczny za wyjaśnienie, dlaczego domyślna implementacja generuje operator==
poprawnie, ale niestandardowa nie.
źródło
Podczas standaryzacji tej funkcji zdecydowano, że równość i porządek powinny być logicznie rozdzielone. W związku z tym zastosowania testów równości (
==
i!=
) nigdy nie będą wywoływaneoperator<=>
. Jednak nadal uważano za użyteczne możliwość domyślnego ustawienia obu z nich za pomocą jednej deklaracji. Więc jeśli domyślnieoperator<=>
, zdecydowano, że masz również zamiar domyślnieoperator==
(chyba że zdefiniujesz to później lub wcześniej zdefiniowałeś).Jak się dlaczego ta decyzja została podjęta , podstawowe rozumowanie wygląda następująco. Zastanów się
std::string
. Porządkowanie dwóch łańcuchów jest leksykograficzne; każdy znak ma wartość całkowitą w porównaniu z każdym znakiem w drugim ciągu. Pierwsza nierówność skutkuje wynikiem zamówienia.Jednak testowanie równości ciągów ma zwarcie. Jeśli dwa ciągi nie są równej długości, nie ma sensu dokonywać porównania pod względem znaków; nie są równi. Więc jeśli ktoś przeprowadza testy równości, nie chcesz robić tego długo, jeśli możesz to zwierać.
Okazuje się, że wiele typów, które wymagają uporządkowania zdefiniowanego przez użytkownika, będzie również oferowało pewien mechanizm zwarciowy do testowania równości. Aby uniemożliwić ludziom wdrażanie tylko
operator<=>
i wyrzucanie potencjalnej wydajności, skutecznie zmuszamy wszystkich do zrobienia obu rzeczy.źródło
Pozostałe odpowiedzi naprawdę dobrze wyjaśniają, dlaczego ten język jest taki. Chciałem tylko dodać, że w przypadku, gdy nie jest to oczywiste, możliwe jest, aby użytkownik otrzymał
operator<=>
domyślnieoperator==
. Musisz tylko napisać domyślnieoperator==
:źródło