Nave espacial es el nombre con el que se conoce al operator<=> introducido en el estándar C++20; hace referencia al operador de comparación de tres vías que es usado para: primero comparar dos objetos, y luego comparar ese resultado con cero.
Una de sus principales ventajas es que reduce el código boilerplate: secciones de código que se repiten en varias partes y son requeridas para una funcionalidad específica, como lo son las secciones de código de los distintos operadores de comparación.

Previo a C++20 se puede encontrar código como el siguiente:

struct S 
{
  int value;

  // Operadores de comparación
  bool operator==(const S& rhs) const { return value == rhs.value; }
  bool operator!=(const S& rhs) const { return !(*this == rhs);    }
  bool operator<(const S& rhs)  const { return value < rhs.value;  }
  bool operator<=(const S& rhs) const { return !(rhs < *this);     }
  bool operator>(const S& rhs)  const { return rhs < *this;        }
  bool operator>=(const S& rhs) const { return !(*this < rhs);     }
};

Allí se definen las comparaciones requeridas para una nueva estructura S.

El código compila y funciona pero puede ser mucho más simple, además puede ser óptimo dejar que el compilador genere estos operadores automáticamente para aprovechar funcionalidades adicionales de ordenamiento.

Comparación de tres vías

Al definir el operador de comparación de tres vías como predeterminado para que lo genere el compilador de manera automática, el código anterior es reducido a:

#include <compare>

struct S
{
  int value;

  // Operador nave espacial
  auto operator<=>(const S&) const = default;
};

El compilador genera todas las comparaciones por defecto. El tipo de retorno puede ser bool, sin embargo es conveniente dejarlo como auto para tener en cuenta el ordenamiento, del cual hablo en la publicación sobre ordenamiento intuitivo.

Usos

¿Por qué definir las comparaciones para una estructura? Suponiendo que se quiere tener una colección de objetos de S que crezca de manera dinámica en memoria contigua, y que se puedan visualizar en la consola. En este caso se puede escoger un contenedor std::vector de la biblioteca STL.

Una de las condiciones para usar la biblioteca STL en una estructura definida por el usuario es que sus objetos se puedan comparar, lo cual se logra con el operador nave espacial.
Crear un vector de S y visualizar sus elementos por medio de un range-based for-loop es tan simple como:

#include <compare>
#include <iostream>
#include <vector>

struct S 
{
  int value;
  auto operator<=>(const S&) const = default;
};

int main()
{
  std::vector<S> vec{{3}, {2}, {1}, {42}};
  std::cout << "vector de S: ";
  for (auto it : vec)
  {
    std::cout << it.value << ' ';
  }
  return 0;
}

El resultado es:

vector de S: 3 2 1 42 

Consideraciones

El operador de comparación de tres vías está disponible en:

  • Estándar: -std=C++20, -std=gnu++2a o -std=c++2a, con biblioteca: libstdc++ 2020.
  • Versión del compilador: gcc > '10.2'

El código mostrado se puede compilar en compiler-explorer.

Fuentes

Deja un comentario