Functors In C++

1 mainWhen you look at the word “functor”, the first thing that comes to mind is that it looks very similar to “function”. The word actually comes from a field called category theory, which is an abstract branch of mathematics. A category basically consists of objects that are linked to each other in certain ways. This is an extremely simplistic view of a very complex field of mathematics. But basically, that’s what it’s about! As it turns out, this mathematical concept is really useful in the world of programming. If used in the right way, it can be a very powerful tool in your coding arsenal. So what exactly is a functor in the context of programming? How do we use it?  

What is a functor and why do we need it?

Simply put, a functor is just a class which defines the operator ‘()’. Now why would we want to do that? Well, this lets you create objects that look like a function. Functors are basically functions with a state. Let’s take the example of C++. Let’s say we want to define a function that can be constructed based on the input argument. Now why would we want to “construct” a function based on the input arguments? Can’t we just define a separate function for every case? Sure, if you want to! But it only works well when we have a fixed number of predefined tasks. But in the real world, we want to construct functions based on many input parameters and we don’t want to construct separate functions for every single case because it tends to become intractable. Also, imagine the amount of overhead you will have if you do that! So to circumvent this whole issue, we have the concept of functors.

2 operationsLet’s say you want to create a function which applies a series of operations to the input. To keep it simple, let’s say we want to multiply the input argument by 7 and then add 12 to it. A simple way of doing it to hard code the two operations i.e. multiplication and addition, along with hardcoding the values 7 and 12. Now instead of adding 7, what if I want to add based on the output of some other function? Instead of multiplication, I may want to pick an operation based on the output of another function. Instead of addition, I want that operation to be a combination of operators, which themselves depend on the outputs of several other functions. You see where we are going with this? Do you see how quickly this becomes intractable? This is the reason functors becomes extremely crucial in developing complex systems.

How does it work in practice?

In C++, we can create functors using a class with one or more private variables to store the state, and using an overloaded operator () to execute the function. Let’s consider the following example:

// This is a functor
class MultiplyX 
{
    public:
        MultiplyX(int input) { x = input; }
        int operator()(int y) { return x * y; }
 
    private:
        int x;
};

// Using a functor
MultiplyX mulX(8); // create an instance of the functor class
int i = mulX(5);   // using the functor
assert(i == 40);   // check if the value of 'i' is 40

vector<int> myInput; // contains a bunch of values
vector<int> myOutput;

// We pass a functor to std::transform as an input argument
// which calls the functor on every element in the input sequence
// and stores the result in the output sequence
std::transform(myInput.begin(), myInput.end(), myOutput.begin(), mulX(3)); 
assert(myOutput[i] == myInput[i] * 3); // for all i

What’s the big deal here? What if I just use a regular function?

One of the biggest advantages of functors over regular functions is that they can contain state. The above example creates a function which multiplies 8 to whatever you give it. But as we know, the value 8 is not hardcoded. We just specified it as a constructor argument when we created our functor instance. We basically “constructed” the function based on the input argument. We can create another function which multiplies the input by 13 just by calling the constructor with a different value. This makes them very customizable!

As we can see from the last few lines in the code, we often pass functors as input arguments to other functions. Now you might say that we can do the same with a regular function pointer? Why do we need fancy functors for that? Well, functors can be customized because they contain state, making them way more flexible than function pointers. If we were to use a function pointer, we would have to write a function which has a predefined functionality. The functor is more general, and multiplies whatever you initialized it with. They are also more efficient. In the above example, the compiler knows exactly which function std::transform should call i.e. mulx::operator(). The compiler can inline that function call, and this makes it just as efficient as manually calling the function on each value of the vector. Isn’t that nice? If I had passed a function pointer instead, the compiler couldn’t immediately see which function it points to, so unless it performs some fairly complex global optimizations, it would have to dereference the pointer at runtime, and then make the call.

——————————————————-———————-—————————-

2 thoughts on “Functors In C++

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s