Skip to main content
The () operator, formally known as the function call operator, is an n-ary operator used to invoke a function, a function pointer, or a callable object. In C++, it evaluates the expression preceding the parentheses and passes the enclosed comma-separated list of arguments to the resulting callable entity, transferring execution control to that entity. When applied to a class instance, the () operator allows the object to behave syntactically like a function. Objects that overload this operator are technically referred to as function objects or functors.

Syntax

The declaration of an overloaded function call operator commonly utilizes the following base structural forms. It is highly flexible and supports standard function specifiers including constexpr, consteval, virtual, and template:
When the compiler encounters an expression like obj(arg1, arg2), it translates it into a direct member function call:

Technical Rules and Constraints

The () operator possesses specific structural rules governing its implementation:
  1. Member Function Requirement: It must be implemented as a member function. It cannot be overloaded as a free (global or namespace-level) function. As of C++23 (P1169R4), it can be declared as a static member function. Prior to C++23, it was strictly required to be non-static.
  2. Arity and Default Arguments: It does not have a fixed arity. The parameter list can contain zero or any number of arguments, and it permits default arguments.
  3. Templates: operator() can be templated. This is the underlying mechanism that enables generic lambdas (e.g., [](auto x) { ... }), where the compiler generates a member template operator().
  4. Explicit Object Parameters (C++23): It supports deducing this via an explicit object parameter (e.g., this auto&& self as the first parameter). This allows the operator to deduce its own value category and type, which is the foundational mechanism for creating recursive lambdas without the overhead of std::function.
  5. CV and Ref Qualifiers: Non-static overloads can be const-qualified, volatile-qualified, or ref-qualified (& or &&). A const-qualified operator() enforces bitwise (shallow) const correctness. It prevents mutation of the object’s direct, non-mutable data members, but does not prevent mutation of data accessed through internal pointers or references.
  6. Virtual and Constexpr: It can be declared virtual to support dynamic dispatch, or constexpr/consteval to enforce compile-time evaluation.

Example of Structural Mechanics

Relationship to Lambda Expressions

At the compiler level, C++ lambda expressions are directly tied to the () operator. When a lambda is defined, the compiler generates an anonymous, non-union class type (the closure type). The body of the lambda is compiled into an inline public operator() within that generated class.
By default, the generated operator() for a lambda is const. The mutable keyword in a lambda declaration explicitly removes this const qualifier from the underlying operator(). In C++17, lambdas can be evaluated at compile-time, which implicitly or explicitly applies the constexpr specifier to the generated operator(). Furthermore, in C++23, lambdas without captures can be explicitly declared with the static keyword, instructing the compiler to generate a static operator().
Tired of Poor C++ Skills? Fix That With Deep Grasping!Learn More