Saltar a contenido

Última actualización:2026-10-12

El operador de comparación de tres vías <=> de C++20

Tres órdenes

El operador de comparación de tres vías <=>, también llamado operador nave espacial, tiene tres órdenes posibles como valor de retorno; a continuación lo analizamos a fondo desde la perspectiva del código fuente de gcc.

Nota: versión para impacientes, el ejemplo de esta sección ya está actualizado en el 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;
}

Salida:

St16partial_ordering
St15strong_ordering
  1. 1.1 <=> 2.2: esto compara dos números de coma flotante. Para los números de coma flotante, la biblioteca estándar devuelve std::partial_ordering, porque la existencia de valores NaN hace que la comparación entre ellos no sea un orden total estricto. std::partial_ordering permite que el resultado sea <, >, == o unordered.

Podemos usar las variables estáticas del código de gcc para ver si partial_ordering es menor, mayor, igual o sin orden:

static const partial_ordering less;
static const partial_ordering equivalent;
static const partial_ordering greater;
static const partial_ordering unordered;

Si forzamos la conversión, obtendremos un error:

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`: esto compara dos enteros. Para los enteros, la biblioteca estándar devuelve `std::strong_ordering`, porque la comparación de enteros es una relación de orden total estricta, sin casos indeterminados. `std::strong_ordering` solo devuelve `<`, `>` o `==`.

De forma análoga, pueden usarse los siguientes 4 miembros estáticos.

static const strong_ordering less;
static const strong_ordering equal;
static const strong_ordering equivalent;
static const strong_ordering greater;

Por tanto, el tipo de c1 es std::partial_ordering, mientras que el de c2 es std::strong_ordering, lo que también explica por qué los tipos mostrados son distintos.

Además de partial_ordering y strong_ordering, <=> también puede devolver weak_ordering, cuyos miembros estáticos son:

static const weak_ordering less;
static const weak_ordering equivalent;
static const weak_ordering greater;

equal y equivalent

En los tres órdenes anteriores puede verse que para la igualdad aparecen dos: equal y equivalent; ¿cuál es la diferencia entre ambos?

Aquí remitimos directamente a cppreference: no hay diferencia entre ambos. Sin embargo, std::strong_ordering es la única categoría que define igualdad. Todas las demás categorías solo definen equivalencia. Esto confirma los miembros estáticos de arriba: strong_ordering tiene dos, mientras que los demás solo tienen equivalent.

Si la comparación produce un orden fuerte entre los elementos comparados, equivalente e igual son lo mismo. La razón de que existan dos palabras para expresarlo es que para los otros tipos de orden no ocurre igual. Los órdenes débil y parcial directamente no tienen igualdad; solo ofrecen equivalencia.

Equivalente significa que dos objetos pueden compararse como iguales. Igual significa algo más fuerte: si se comparan como iguales, uno puede sustituir al otro en cualquier uso const; es decir, siempre que a == b sea cierto, la propiedad f(a) == f(b) es cierta, donde f denota una función que solo lee el estado de comparación relevante accesible mediante los miembros const públicos del parámetro. Si la comparación de un tipo permite la igualdad (requisito del orden fuerte), también permite la equivalencia. Por eso, para las comparaciones de orden fuerte, son lo mismo.

https://en.cppreference.com/w/cpp/utility/compare/strong_ordering

¿Por qué usar el operador de comparación de tres vías?

El operador de comparación de tres vías (<=>) permite determinar la relación de orden entre dos valores en una sola operación, mientras que los operadores de comparación tradicionales requieren varias comparaciones.

Limitaciones de los operadores de comparación tradicionales:

  • Si a == b es falso, no puedes saber si a < b o a > b.
  • Si a != b es cierto, no puedes saber si a < b o a > b.
  • Si a < b es falso, no puedes saber si a == b o a > b.
  • Si a > b es falso, no puedes saber si a == b o a < b.
  • Si a <= b es cierto, no puedes saber si a == b o a < b.
  • Si a >= b es cierto, no puedes saber si a == b o a > b.

Estas limitaciones muestran que los operadores de comparación tradicionales no pueden determinar de una sola vez la relación completa entre dos valores, sino que requieren varias comparaciones para obtener el resultado íntegro.

Fin de esta sección

Temas relacionados

Comentarios