Operátor <=> v C++20: Překvapivé chování při vlastních implementacích
C++20 přineslo mnoho novinek, mezi nimi i tzv. spaceship operator <=>, který umožňuje snadnější implementaci porovnávacích operátorů. Tento operátor je užitečný zejména pro třídy, kde je potřeba porovnávat objekty podle více členů. Nicméně při jeho použití existuje jedno potenciálně překvapivé chování, které je důležité pochopit, zejména pokud implementujete vlastní verzi tohoto operátoru.
Automatická generace operátorů při použití <=>
Pokud použijete výchozí implementaci operátoru <=> (pomocí klíčového slova default), kompilátor automaticky vygeneruje nejen porovnávací operátory <, <=, >, >=, ale také operátory rovnosti == a !=. To znamená, že výchozí implementace <=> zajistí kompletní sadu porovnávacích operátorů.
Příklad:
#include <compare>
struct A {
int x;
int y;
auto operator<=>(const A&) const = default;
};
V tomto případě kompilátor automaticky vygeneruje všechny potřebné operátory, včetně == a !=, které budou provádět porovnání jednotlivých členů struktury A.
Vlastní implementace <=> a problém s rovností
Pokud se rozhodnete implementovat operátor <=> ručně, například kvůli specifickým požadavkům na výkon nebo logiku porovnání, kompilátor negenereuje operátory rovnosti == a != automaticky. To znamená, že pokud chcete, aby vaše třída podporovala porovnání rovnosti, musíte explicitně implementovat operátor ==.
Příklad:
struct B {
int x;
int y;
auto operator<=>(const B& other) const {
auto cmp = x <=> other.x;
if (!std::is_eq(cmp)) return cmp;
return y <=> other.y;
}
};
V tomto případě třída B podporuje pouze porovnávací operátory <, <=, >, >=, ale nikoliv == a !=. Pokud byste se pokusili použít == na objekty typu B, kompilátor by vyhodil chybu.
Jak přidat podporu pro ==?
Pokud chcete, aby vaše třída podporovala i operátory rovnosti, musíte explicitně implementovat operátor ==. V kombinaci s vlastním <=> můžete použít klíčové slovo default, aby byl operátor == generován automaticky na základě porovnání jednotlivých členů.
Příklad:
struct C {
int x;
int y;
auto operator<=>(const C& other) const {
auto cmp = x <=> other.x;
if (!std::is_eq(cmp)) return cmp;
return y <=> other.y;
}
bool operator==(const C&) const = default;
};
V tomto případě třída C podporuje jak porovnávací operátory <, <=, >, >=, tak i operátory rovnosti == a !=.
Proč kompilátor negeneruje == automaticky při vlastním <=>?
Důvodem je, že vlastní implementace <=> může obsahovat specifickou logiku, která by mohla být v rozporu s automaticky generovaným operátorem ==. Například pokud <=> porovnává pouze část členů třídy, výchozí == by mohl vést k nesprávným výsledkům. Proto je na vývojáři, aby explicitně určil, zda a jak má být rovnost porovnávána.
Shrnutí
- Výchozí
<=>: Automaticky generuje všechny porovnávací operátory, včetně==a!=. - Vlastní
<=>: Generuje pouze<,<=,>,>=. Operátory==a!=musíte implementovat ručně. - Doporučení: Pokud potřebujete podporu pro
==, použijtebool operator==(const T&) const = default;pro snadnou implementaci.
Operátor <=> je mocný nástroj, ale jeho správné použití vyžaduje pochopení toho, jak funguje automatická generace operátorů.