Overloading the Function Call Operator in C++
In C++, overloading the function call operator,
operator(), allows an instance of a class or struct to be
invoked using standard function call syntax. These callable objects are
known as functors or function objects.
This article explains how to overload this operator, highlights the key
advantages of functors over standard functions—particularly their
ability to maintain internal state—and demonstrates practical examples,
including their use with the Standard Template Library (STL).
What is a Functor?
A functor is any object that can be called as if it were a function. While a regular function executes a block of code, a functor combines executable code with object-oriented capabilities such as member variables, constructors, and encapsulation.
To create a functor, you define a class or struct and implement a
member function named operator().
Basic Syntax and Implementation
The signature for overloading the function call operator can accept any number of arguments and return any type, just like a regular function.
#include <iostream>
class Greeter {
public:
// Overloading operator() with one parameter
void operator()(const std::string& name) const {
std::cout << "Hello, " << name << "!\n";
}
};
int main() {
Greeter greet;
// Invoking the object as a function
greet("Alice");
greet("Bob");
return 0;
}In this example, greet("Alice") is syntactically
equivalent to calling the member function
greet.operator()("Alice").
Maintaining State
The primary advantage of a functor over a regular function pointer is its ability to retain state across multiple invocations without relying on global variables.
#include <iostream>
class Multiplier {
private:
int factor;
public:
// Constructor initializes the state
explicit Multiplier(int f) : factor(f) {}
// Operator() uses the internal state
int operator()(int value) const {
return value * factor;
}
};
int main() {
Multiplier triple(3);
Multiplier quintuple(5);
std::cout << triple(10) << "\n"; // Outputs: 30
std::cout << quintuple(10) << "\n"; // Outputs: 50
return 0;
}Here, triple and quintuple are two
instances of the same class, but each maintains its own independent
state.
Overloading with Multiple Signatures
Like other member functions in C++, operator() can be
overloaded to handle different argument types, counts, or return types
within the same class.
class Formatter {
public:
void operator()(int n) const {
std::cout << "Integer: " << n << "\n";
}
void operator()(double d) const {
std::cout << "Float: " << d << "\n";
}
void operator()(const std::string& s, bool uppercase) const {
std::cout << "String: " << s << (uppercase ? " [UPPER]" : "") << "\n";
}
};Using Functors with the Standard Template Library (STL)
Functors are widely used with STL algorithms such as
std::sort, std::for_each, and
std::transform. Because functors have distinct types, the
compiler can often inline the function call, yielding performance
benefits over raw function pointers.
#include <iostream>
#include <vector>
#include <algorithm>
struct CountDivisibleBy {
int divisor;
int count = 0;
explicit CountDivisibleBy(int d) : divisor(d) {}
void operator()(int n) {
if (n % divisor == 0) {
++count;
}
}
};
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// Pass functor to algorithm by value
CountDivisibleBy result = std::for_each(numbers.begin(), numbers.end(), CountDivisibleBy(2));
std::cout << "Count of numbers divisible by 2: " << result.count << "\n"; // Outputs: 5
return 0;
}In this case, std::for_each processes every element in
the collection using the functor and returns the modified functor
containing the accumulated state.