How To Create Functors and Function Objects
Written by Mike James   
Monday, 17 June 2024
Article Index
How To Create Functors and Function Objects
Creating a Functor
Passing function objects

Creating a Functor

Now we can put this to a slightly different use by overloading the function operator (). The () operator evaluates the function to its left and this is an operator that can be redefined. For example, if you want a function that adds one to its parameter and returns the result you can code this as:

public class MyFunctor
{
public:
int operator () (int i)
{
return ++i;
}
};

To make use of this function object you have to instantiate it and this is about the only real difference you will notice in the use of a function object as opposed to a function that does the same job:

MyFunctor MyFunction;
int result=MyFunction(1);

Notice that even though MyFunction looks like a function it really is an object. That is MyFunctor can have properties, methods, constructors and destructors in addition to the function it implements and it can be passed to other functions just like any other object.

A complete program using MyFunctor is:

#include <iostream>
using namespace std;
class MyFunctor
{
public:
    int operator()(int i)
    {
        return ++i;
    }
};
int main()
{
    MyFunctor MyFunction;
    int result = MyFunction(1);
    std::cout<<result;
}

State

So now we have a function object and while is looks clever you might be wondering what use they are in general. The first thing to say is that function objects fit better with the "everything is an object" view of programming so even if there were no practical advantages you still might want to use them.

However theory aside the key importance of function objects is that they allow you to associate state with a function. That is a function object can be initialized to a given state and can record what happens to it i.e. change state. 

For example, if you want to create a function that adds a specified increment to its input then you simply have to add a constructor:

class MyFunctor
{
private:
int inc;
public:
MyFunctor(int value)
{
inc=value;
};
int operator () (int i)
{
return i+inc;
}
};

Now when you create an instance of MyFunctor you have to specify the increment to be used in subsequent calls:

MyFunctor MyFunction(2);
int result=MyFunction(1);

Now MyFunction always adds two to its input.

Not only can you set the initial state you can modify it as the function is used. For example to count the number of times an instance has been used all you need to do is add a counter and remember to increment it within the function:

class MyFunctor
{
private:
int inc;
int count;
public:
MyFunctor(int value)
{
count=0;
inc=value;
};

int operator () (int i)
{
count++;
return i+inc;
}
};

Now every time you call an instance of MyFunctor count is incremented.

Sometimes this ability to store a state is referred to as a sort of "closure" and indeed it can be used in this way. The big difference between using a function object in this way and true closure is that in true closure the state of the function is set automatically but using function objects you have to set the state manually. We will look at an example of this after considering function objects as an alternative to function pointers.

A complete program using the new MyFunctor is:

#include <iostream>
using namespace std;
class MyFunctor
{
private:
    int inc;
    int count;
public:
    MyFunctor(int value)
    {
        count = 0;
        inc = value;
    };
    int operator()(int i)
    {
        count++;
        return i + inc;
    }
};
int main()
{
    MyFunctor MyFunction(2);
    int result = MyFunction(1);
    std::cout << result;
}



Last Updated ( Monday, 17 June 2024 )