The Spaceship Operator and Expression Rewriting

Niche Cases for Three-Way Comparison

How does the C++20 standard handle types that do not naturally fit into the three-way comparison model?

Abstract art representing computer programming

The C++20 standard's three-way comparison model (<=>) is versatile, but there are types and situations where it might not fit naturally. Here's how C++20 handles such cases and what you can do:

Complex Types

For complex types, where simple comparison logic might not be straightforward, you can still define a meaningful <=> operator by focusing on the most relevant attributes for comparison.

Example: Complex Numbers

Consider complex numbers where comparing the magnitude is more meaningful than comparing the real and imaginary parts separately:

#include <cmath>
#include <compare>
#include <complex>
#include <iostream>

class ComplexNumber {
 public:
  ComplexNumber(double real, double imag)
    : Real{real}, Imag{imag} {}

  std::partial_ordering operator<=>(
    const ComplexNumber& Other) const {
    double mag1 = std::sqrt(
      Real * Real + Imag * Imag
    );
    double mag2 = std::sqrt(
      Other.Real * Other.Real + Other.Imag * Other.Imag
    );
    return mag1 <=> mag2;
  }

  bool operator==(const ComplexNumber& Other) const {
    return Real == Other.Real && Imag == Other.Imag;
  }

 private:
  double Real, Imag;
};

int main() {
  ComplexNumber num1{3, 4};
  ComplexNumber num2{5, 12};

  if (num1 < num2) {
    std::cout
      << "num1 has a smaller magnitude than num2\n";
  } else if (num1 > num2) {
    std::cout
      << "num1 has a larger magnitude than num2\n";
  } else {
    std::cout
      << "num1 and num2 have the same magnitude\n";
  }
}
num1 has a smaller magnitude than num2

Non-Comparable Types

For types where comparison doesn’t make sense (like a function object or a file handle), you should not define <=>. Instead, you might provide specialized comparison functions if any form of comparison is needed.

Custom Comparison Logic

If your type has a unique way of determining order, you can encapsulate this in the <=> operator. For instance, a Version class comparing major, minor, and patch numbers can be handled like this:

#include <compare>
#include <iostream>

class Version {
 public:
  Version(int major, int minor, int patch)
    : Major{major}, Minor{minor}, Patch{patch} {}

  std::strong_ordering operator<=>(
    const Version& Other) const {
    if (auto cmp = Major <=> Other.Major; cmp != 0)
      return cmp;
    if (auto cmp = Minor <=> Other.Minor; cmp != 0)
      return cmp;
    return Patch <=> Other.Patch;
  }

  bool operator==(const Version& Other) const {
    return std::tie(Major, Minor, Patch) ==
      std::tie(Other.Major, Other.Minor, Other.Patch);
  }

 private:
  int Major, Minor, Patch;
};

int main() {
  Version v1{1, 0, 0};
  Version v2{1, 1, 0};

  if (v1 < v2) {
    std::cout << "v1 is older than v2";
  } else if (v1 > v2) {
    std::cout << "v1 is newer than v2";
  } else {
    std::cout << "v1 and v2 are the same version";
  }
}
v1 is older than v2

Conclusion

The C++20 standard is flexible and allows you to implement <=> even for complex or niche cases.

By focusing on meaningful comparisons and encapsulating the logic within the <=> operator, you can leverage the power of three-way comparison for a wide range of types.

This Question is from the Lesson:

The Spaceship Operator and Expression Rewriting

A guide to simplifying our comparison operators using C++20 features

Answers to questions are automatically generated and may not have been reviewed.

This Question is from the Lesson:

The Spaceship Operator and Expression Rewriting

A guide to simplifying our comparison operators using C++20 features

A computer programmer
Part of the course:

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Free, unlimited access

This course includes:

  • 125 Lessons
  • 550+ Code Samples
  • 96% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved