Skip to content

Comparators

GitHub Action edited this page Sep 21, 2025 · 16 revisions

The comparators described below can be used as needed with sorters and sorter adapters that accept comparisons. Every comparator in this module satisfies the BinaryPredicate library concept.

Every non-refined comparator described below is also a transparent comparator. While this ability is not used by the library itself, it means that the comparators can be used with the standard library associative containers to compare heterogeneous objects without having to create temporaries.

Total order comparators

#include <cpp-sort/comparators/total_greater.h>
#include <cpp-sort/comparators/total_less.h>

The comparators total_less and total_order are customization points implementing a total order, inspired by the similar functions described in P0100. The provided functions handle built-in integer out of the box (using the built-in relational operators) and implement IEEE 754's totalOrder for floating point numbers (from lesser to greater):

  • positive quiet NaNs
  • positive signaling NaNs
  • positive infinity
  • positive reals
  • positive zero
  • negative zero
  • negative reals
  • negative infinity
  • negative signaling NaNs
  • negative quiet NaNs

That said, the comparators are currently unable to discriminate between quiet and signaling NaNs, so they are considered to be equivalent. When it doesn't handle a type natively and ADL doesn't find any suitable total_less function in a class namespace, cppsort::total_less does not fall back to operator<; see P0100 for the rationale (it applies to the whole total_* family of customization points).

Total order comparators are considered as generating branchless code when comparing instances of a type that satisfies std::is_integral.

Weak order comparators

#include <cpp-sort/comparators/weak_greater.h>
#include <cpp-sort/comparators/weak_less.h>

The comparators weak_less and weak_order are customization points implementing a weak order, inspired by the similar functions described in P0100. The provided functions handle built-in integer out of the box (falling back to total_* functions) and implement a weak order for floating point numbers as suggested by Lawrence Crowl in his CppCon 2015 presentation (from lesser to greater):

  • all positive NaNs equivalent
  • positive infinity
  • positive reals
  • all zeros equivalent
  • negative reals
  • negative infinity
  • all negative NaNs equivalent

When it doesn't handle a type natively and ADL doesn't find any suitable weak_less function in a class namespace, cppsort::weak_less falls back to cppsort::total_less since a total order is also a weak order (it applies to the whole weak_* family of customization points).

Weak order comparators are considered as generating branchless code when comparing instances of a type that satisfies std::is_integral.

Partial order comparators

#include <cpp-sort/comparators/partial_greater.h>
#include <cpp-sort/comparators/partial_less.h>

The comparators partial_less and partial_order are customization points implementing a partial order, inspired by the similar functions described in P0100. The provided functions handle built-in integer out of the box (falling back to weak_* functions) and implement a partial order for floating point numbers using the built-in relational operators.

When it doesn't handle a type natively and ADL doesn't find any suitable partial_less function in a class namespace, cppsort::partial_less falls back to cppsort::weak_less since a weak order is also a partial order (it applies to the whole partial_* family of customization points).

Partial order comparators are considered as generating branchless code when comparing instances of a type that satisfies std::is_arithmetic.

Natural order comparator

#include <cpp-sort/comparators/natural_less.h>

The comparator natural_less is a customization point that can be used to perform a natural sort. The function handles any two forward ranges of char out of the box using std::isdigit to identify digits (which includes std::string, std::vector<char> and char[]). Other character types and locales are currently not handled and it is unlikely that the library will evolve more than switching to <locale>'s std::isdigit instead of <cctype>'s one.

Case-insensitive comparator

#include <cpp-sort/comparators/case_insensitive_less.h>

The comparator case_insensitive_less is a customization point that be used to perform a case-insensitive sort on collections. The function handles any forward range of char or wchar_t out of the box using std::ctype::tolower prior to character comparison. The customization point has two distinct signatures:

template<typename T>
bool case_insensitive_less(const T& lhs, const T& rhs);

template<typename T>
bool case_insensitive_less(const T& lhs, const T& rhs, const std::locale& loc);

case_insensitive_less can indeed be passed an std::locale that will be used to perform the tolower operation. If it's not passed a locale, it will use the global locale instead:

// Use global locale
sort(sequence, case_insensitive_less);

// Use classic C locale
sort(sequence, case_insensitive_less(std::locale::classic()));

The two-parameter version of the customization point calls the three-parameter one with std::locale::global() as the third argument, so customizing only the three-parameter version will also extend the customization to the two-parameter one.

This comparator can be refined for a specific type to provide better performance.

Clone this wiki locally