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 operator keyword in C++ is a language construct used to define custom semantics for built-in operators when applied to user-defined types (classes, structs, or enumerations). This mechanism, known as operator overloading, maps standard symbolic operations to specific function calls, allowing the compiler to resolve expressions involving custom types.

Syntax

Operator functions can be declared as either member functions or non-member (free/friend) functions. The following code demonstrates valid syntax for various operator declarations:
struct CustomType {
    int value;

    // 1. Member Function Syntax (e.g., binary +)
    // The left-hand operand is the implicit 'this' instance.
    CustomType operator+(const CustomType& right_operand) const {
        return CustomType{value + right_operand.value};
    }

    // 2. Type Conversion Operator Syntax
    // No return type is specified; it is deduced from the operator name.
    explicit operator int() const {
        return value;
    }
};

// 3. Non-Member Function Syntax (e.g., binary -)
// Both operands are passed explicitly.
CustomType operator-(const CustomType& left_operand, const CustomType& right_operand) {
    return CustomType{left_operand.value - right_operand.value};
}

// 4. User-Defined Literal Syntax
CustomType operator""_suffix(unsigned long long literal_value) {
    return CustomType{static_cast<int>(literal_value)};
}

Compiler Translation Mechanics

When the C++ compiler encounters an expression containing an operator (e.g., a @ b, where @ represents a valid operator), it performs name lookup and overload resolution. The expression is statically translated into a function call:
  • Binary Operators: a @ b translates to a.operator@(b) (member resolution) or operator@(a, b) (non-member resolution).
  • Unary Operators: @a translates to a.operator@() or operator@(a).
  • Postfix Operators: a@ (like a++) translates to a.operator@(int) or operator@(a, int). The int parameter is a dummy value used exclusively for overload resolution to distinguish postfix from prefix operations.

Arity and Parameter Rules

The arity (number of operands) of an operator dictates the parameter count of the operator function:
  1. Unary Operators (+, -, !, ~, *, &, ++, --):
    • Member: 0 parameters (operates on this).
    • Non-member: 1 parameter.
  2. Binary Operators (+, -, *, /, %, ==, <, &&, etc.):
    • Member: 1 parameter (the right-hand side).
    • Non-member: 2 parameters (left-hand side, right-hand side).

Structural Restrictions and Caveats

The C++ standard imposes strict limitations on the operator keyword to maintain parsing consistency:
  • Immutability of Grammar: You cannot change the precedence, associativity, or arity of an operator.
  • Symbol Restriction: You cannot invent new operators (e.g., operator** is invalid).
  • Operand Requirement: At least one operand must be a user-defined type. You cannot overload operators exclusively for fundamental types (e.g., redefining int + int).
  • Short-Circuit Evaluation Loss: Overloading the logical operators (&& and ||) causes them to lose their short-circuit evaluation properties. Because overloaded operators are resolved as standard function calls, all operands are evaluated prior to invocation, fundamentally altering the expected behavior of these operators.
  • Non-Overloadable Operators: The following operators cannot be overloaded:
    • Scope resolution: ::
    • Member access: .
    • Member pointer access: .*
    • Ternary conditional: ?:
    • Object size/type: sizeof, typeid, alignof
  • Member-Only Operators: The following operators must be implemented as non-static member functions; they cannot be free functions:
    • Assignment: operator=
    • Subscript: operator[]
    • Function call: operator()
    • Member access via pointer: operator->

Special Operator Forms

  • Function Call Operator (operator()): Allows an object to be invoked as if it were a function. Objects implementing this are termed functors or function objects. Prior to C++23, it was the only operator that supported an arbitrary number of parameters.
  • Subscript Operator (operator[]): Accesses elements. As of C++23, this operator supports multidimensional subscripting, allowing it to also accept an arbitrary number of parameters.
  • Allocation/Deallocation (operator new / operator delete): These manage memory allocation at the class or global level. They operate on raw bytes (std::size_t) rather than typed objects and are implicitly static when declared as class members.
  • Spaceship Operator (operator<=>): Introduced in C++20, the three-way comparison operator can be defaulted (= default;). Doing so generates the <=> function and implicitly defaults operator==. It does not generate functions for <, >, <=, >=, or !=. Instead, the compiler uses expression rewriting to evaluate those operations using the existing <=> and == functions.
Master C++ with Deep Grasping Methodology!Learn More