Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The < (less than) operator is a binary relational operator that evaluates whether its left-hand operand is strictly less than its right-hand operand, returning a bool (true or false).
lhs < rhs

Mechanics for Built-in Types

For fundamental types, the compiler generates direct comparison instructions based on the operand types:
  • Arithmetic Types: Evaluates numeric values. If operands are of different types (e.g., int and double), the compiler applies standard arithmetic conversions to bring them to a common type before comparison.
    • Warning: These conversions create a notorious pitfall when comparing signed and unsigned integers. Expressions like -1 < 1u evaluate to false because the signed integer (-1) is implicitly converted to a large unsigned value before the comparison. C++20 introduces std::cmp_less (<utility>) as a safe alternative that correctly compares integers of different signedness without unexpected conversions.
  • Pointers: Evaluates memory addresses. According to the C++ standard, built-in pointer comparison using < yields defined behavior only if both pointers point to elements within the same array (or one past the last element), or if they point to different non-static data members of the same object. In the latter case, the later-declared member compares greater, provided both members share the same access control and are not part of a union. Comparing pointers to unrelated objects results in unspecified behavior.
    • Strict Total Ordering: Because the built-in < operator yields unspecified behavior for unrelated pointers, the standard library provides std::less<T*>. This template specialization guarantees a strict total order across all valid pointers of the same type, which is exactly why std::less is the default comparator for associative containers like std::map and std::set.
  • Enumerations: Evaluates the underlying integer values of the enumerators.

Operator Overloading

For user-defined types (classes and structs), the < operator must be explicitly overloaded. It can be implemented as either a member function or a non-member (often friend) function. Member Function Syntax:
class Type {
    int value;
public:
    bool operator<(const Type& rhs) const {
        return this->value < rhs.value;
    }
};
Non-Member Function Syntax:
class Type {
    int value;
public:
    // Constructor and other members...
    friend bool operator<(const Type& lhs, const Type& rhs);
};

bool operator<(const Type& lhs, const Type& rhs) {
    return lhs.value < rhs.value;
}

Strict Weak Ordering Requirement

When overloading the < operator, the implementation must satisfy the mathematical properties of Strict Weak Ordering. The C++ Standard Library relies heavily on this contract. The properties are:
  1. Irreflexivity: x < x must always evaluate to false.
  2. Asymmetry: If x < y is true, then y < x must evaluate to false.
  3. Transitivity: If x < y is true and y < z is true, then x < z must evaluate to true.
  4. Transitivity of Equivalence: If x is equivalent to y (meaning !(x < y) && !(y < x)), and y is equivalent to z, then x must be equivalent to z.
Failure to adhere to strict weak ordering results in undefined behavior when the type is passed to standard library algorithms or associative containers.

C++20 and the Spaceship Operator

Starting in C++20, the explicit overloading of the < operator is largely superseded by the three-way comparison operator (<=>). If a class defines or defaults operator<=>, the compiler will automatically synthesize the < operator (along with >, <=, and >=) by rewriting the expression lhs < rhs as (lhs <=> rhs) < 0.
#include <compare>

struct Point {
    int x;
    int y;
    
    // Compiler automatically generates operator< based on this
    auto operator<=>(const Point&) const = default; 
};
Master C++ with Deep Grasping Methodology!Learn More