Another option we have for implementing first-class functions in C++ is function objects. Function objects are sometimes also referred to as functors.
Creating functors involves operator overloading. We’ve previously seen how we can overload operators like ++
in our custom class code.
The syntax we use to call functions, ()
, is also an operator, and so can be overloaded in the same way:
class Functor {
public:
void operator()() const {
std::cout << "Hello world!";
}
};
The double set of ()
here might seem weird, but it is consistent with the syntax we use for other operator overloads. For example, we’d overload ++
like this:
void operator++() {};
So, given we’re overloading the ()
operator, replacing ++
with ()
might make more sense.
Now, with our when we have an instance of this object, we can “call” it:
int main() {
Functor MyFunctor;
MyFunctor();
}
A common mistake here is to use the ()
operator with the class, rather than an object. This code will compile, but it is calling the class constructor, rather than our operator overload:
int main() {
Functor();
}
Given the constructor returns an instance of the object, we could chain an additional ()
to this expression, which would then call our overload on the object that was constructed:
int main() {
Functor()();
}
Like any object, this can be passed around to other functions, as either a copy or a reference. Therefore, functors allow us to implement the behavior of first-class functions:
void CallIfEven(int n, auto callback) {
if (n%2 == 0) callback();
}
int main() {
Functor MyFunctor;
CallIfEven(2, MyFunctor);
}
A function object might look a lot like a function, particularly given it is “callable” using the same code. But, it’s not strictly correct to refer to it as a function.
Things that can be “called” (or invoked) in programming languages are often referred to as “callables”. Functions are an example of callables, but not all callables are functions.
As with regular functions, we can return values from functors. We do that by replacing the void
in our overload to the type we want to return, and then use appropriate return
 statements:
#include <iostream>
class Functor {
public:
int operator()() const {
return 5;
}
};
int main() {
Functor MyFunctor;
std::cout << MyFunctor();
}
Within the second set of brackets, we can allow our functors to accept arguments:
#include <iostream>
class Functor {
public:
int operator()(int x, int y) const {
return x + y;
}
};
int main() {
Functor MyFunctor;
std::cout << MyFunctor(2, 3);
}
This also means we can overload the ()
operator multiple times within the same class, as long as our parameter lists are unique:
#include <iostream>
class Functor {
public:
void operator()() const {
std::cout << "Hello World\n";
}
void operator()(int x) const {
std::cout << "Hello Integer\n";
}
};
int main() {
Functor MyFunctor;
MyFunctor();
MyFunctor(5);
}
Hello World
Hello Integer
Functors have a lot more power than simple function pointers. Being instances of classes, we naturally have all the power that brings with it. For example:
.
operatorHowever, the most common use case for functors is simply when we require a callable with some persistent state.
For example, here, we have a functor that returns how many times it has been called:
class Functor {
public:
void operator()() {
std::cout << "I have been called "
<< ++Invocations
<< " time(s)\n";
}
private:
int Invocations { 0 };
};
int main() {
Functor MyFunctor;
MyFunctor();
MyFunctor();
MyFunctor();
}
I have been called 1 time(s)
I have been called 2 time(s)
I have been called 3 time(s)
Implementing similar behavior with a regular function wouldn’t be quite so easy to encapsulate.
Remember, as with any object, a functor passed to another function is going to be passed by value by default.
Here, our CallIfEven
function is receiving copies of our function object:
void CallIfEven(int n, auto callback) {
if (n%2 == 0) callback();
}
When our reason for using the functor is to maintain some internal state, this is generally not what we want to happen:
int main() {
Functor MyFunctor;
MyFunctor();
CallIfEven(2, MyFunctor);
MyFunctor();
}
I have been called 1 time(s)
I have been called 2 time(s)
I have been called 2 time(s)
Instead, we typically want to pass our functors by reference, using the &
 syntax:
void CallIfEven(int n, auto& callback) {
if (n%2 == 0) callback();
}
I have been called 1 time(s)
I have been called 2 time(s)
I have been called 3 time(s)
Comprehensive course covering advanced concepts, and how to use them on large-scale projects.