Última atualização:2026-10-12
Operador de comparação de três vias <=> no C++20¶
Três tipos de ordenação¶
O operador de comparação de três vias <=>, também chamado de operador spaceship (nave espacial), possui três tipos de ordenação como valores de retorno; a seguir, vamos nos aprofundar sob a ótica do código-fonte do gcc.
Obs.: versão para quem tem pressa, o exemplo desta seção já foi atualizado no Planeta.
Uso: <=>
#include <compare>
#include <iostream>
int main() {
auto c1 = 1.1 <=> 2.2;
auto c2 = -1 <=> 1;
std::cout << typeid(c1).name() << std::endl;
std::cout << typeid(c2).name() << std::endl;
}
Saída:
1.1 <=> 2.2: esta é uma comparação entre dois números de ponto flutuante. Para números de ponto flutuante, a biblioteca padrão retornastd::partial_ordering, pois a existência de valores NaN faz com que a comparação entre eles não seja uma ordem total estrita.std::partial_orderingpermite que o resultado seja<,>,==ouunordered.
Podemos usar as variáveis estáticas do código do gcc para ver se o partial_ordering é menor, maior, igual ou não ordenado:
static const partial_ordering less;
static const partial_ordering equivalent;
static const partial_ordering greater;
static const partial_ordering unordered;
Se forçarmos a conversão, obteremos um erro:
comp.cc:6:36: error: conversion from 'std::partial_ordering' to non-scalar type 'std::strong_ordering' requested
6 | std::strong_ordering c1 = 1.1 <=> 2.2;
2. `-1 <=> 1`: esta é uma comparação entre dois inteiros. Para inteiros, a biblioteca padrão retorna `std::strong_ordering`, pois a comparação de inteiros é uma relação de ordem total estrita, sem casos indeterminados. `std::strong_ordering` só retorna `<`, `>` ou `==`.
De forma análoga, podem-se usar os 4 membros estáticos a seguir.
static const strong_ordering less;
static const strong_ordering equal;
static const strong_ordering equivalent;
static const strong_ordering greater;
Portanto, o tipo de c1 é std::partial_ordering, enquanto o de c2 é std::strong_ordering, o que também explica por que os tipos impressos são diferentes.
Além de partial_ordering e strong_ordering, <=> também pode retornar weak_ordering, cujos membros estáticos são:
static const weak_ordering less;
static const weak_ordering equivalent;
static const weak_ordering greater;
equal e equivalent¶
Nas três ordenações acima, vê-se que para a igualdade aparecem duas: equal e equivalent. Qual é a diferença entre elas?
Aqui, consultando diretamente o cppreference: não há diferença entre elas. No entanto, std::strong_ordering é a única categoria que define igualdade (equality). Todas as outras categorias definem apenas equivalência (equivalence). Isso confirma exatamente os membros estáticos vistos acima: para string_ordering há dois, e para as demais há apenas equivalent.
Se a comparação produz uma ordenação forte entre os itens comparados, então equivalência e igualdade são a mesma coisa. A razão de existirem duas palavras para isso é que, para os outros tipos de ordenação, não é assim. Ordenações fracas e parciais simplesmente não têm igualdade; elas fornecem apenas equivalência.
Equivalência significa que dois objetos podem comparar-se como iguais. Igualdade significa algo mais forte: se eles comparam iguais, um pode substituir o outro em qualquer uso const; desde que a == b seja verdadeiro, vale a propriedade de que f(a) == f(b), em que f denota uma função que apenas lê o estado saliente comparável acessível por meio dos membros const públicos do argumento. Se a comparação de um tipo permite igualdade (que é um requisito da ordenação forte), ela também permite equivalência. Portanto, para comparações com ordenação forte, elas são a mesma coisa.
https://en.cppreference.com/w/cpp/utility/compare/strong_ordering
Por que usar o operador de comparação de três vias?¶
O operador de comparação de três vias (<=>) permite determinar a relação de ordenação entre dois valores em uma única operação, enquanto os operadores de comparação tradicionais exigem múltiplas comparações.
Limitações dos operadores de comparação tradicionais:
- Se
a == bé falso, você não sabe sea < boua > b. - Se
a != bé verdadeiro, você não sabe sea < boua > b. - Se
a < bé falso, você não sabe sea == boua > b. - Se
a > bé falso, você não sabe sea == boua < b. - Se
a <= bé verdadeiro, você não sabe sea == boua < b. - Se
a >= bé verdadeiro, você não sabe sea == boua > b.
Essas limitações mostram que os operadores de comparação tradicionais não conseguem determinar de uma só vez a relação completa entre dois valores: são necessárias múltiplas comparações para obter o resultado completo.
Fim desta seção
Tópicos relacionados¶
- Introdução às corrotinas no C++20 | C++那些事
- Prática com channel no C++20 | C++那些事
- Concepts (conceitos) no C++20 | C++那些事
- constexpr e a expressão vírgula no C++20 | C++那些事
- Ordem de bytes (endian) no C++20 | C++那些事
- Expressões Lambda no C++20 (parte 1) | C++那些事
- Módulos (Modules) no C++20 | C++那些事
- Biblioteca Ranges do C++20 | C++那些事
- Design e armadilhas do std::span no C++20 | C++那些事
- Guia dos novos recursos do C++20 | C++那些事