Functors and Function Objects
Written by Mike James   
Monday, 15 August 2011
Article Index
Functors and Function Objects
Associating state with functions

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:

public 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:

public 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.

Passing function objects

As a function object is just a standard object you can pass it as a parameter in another method. For example:

public class MyClass
{
public:
void MyMethod(MyFunctor F)
{
int result=F(1);
}
};

Notice that MyMethod accepts a parameter of type MyFunctor and when supplied simply calls it as a function. For example:

MyFunctor MyFunction(2);
MyClass MyObject;
MyObject.MyMethod(MyFunction);

Comparing this to using a function pointer you can see that not only is it simpler, it fits in much better with the object-oriented idea. However, it has to be admitted that you can't do the same fancy tricks that you can achieve with a pointer - for example changing the function the pointer references at run time. This said function object are heavily used in the STL to pass functions - often predicates - into methods.

An example of closure

Returning for a moment to the idea that function object allow C++ programmers to implement closure we can see how this works with a simple example. One of the common uses of closure is to allow a callback function to access variables that are defined within its original context. For example suppose you have to supply a callback function to an object that searches an index for a target. You could implement a cut off value that aborted the search when the number of hits reaches a limit. If C++ implemented closure you could do this as follows.

First define the callback as a function object:

int operator () (Results Rs)
{
if(Rs.Hits>HitLimit) abort;
}

where it is assumed that the callback accepts an object of type Results that the search object uses to communicate the progress of the search. Notice that the signature of the callback function is predefined by the object using the callback - you can't change it.

This is all fairly simply except for where the HitLimit variable comes from. Notice that you can't include HitLimit as a parameter in the callback function because it has to fit the specification supplied for the callback. If C++ supported closure directly we could just create HitLimit as a local variable in the same scope as the function - closure would then make the variable available within the function even if the local context had been destroyed. That is, if C++ supported closure you could just write:

int HitLimit=5;
MyObject.MyMethod(MyFunction);

Yes this would be enough to make HitLimit accessible within MyFunction if closure was in effect.

However we all know that C++ doesn't implement closure so what you have to do is simply add a suitable property to the function object or use the constructor to initialize a private variable:

public class MyFunctor
{
private:
int HitLimit;
public:
MyFunctor(int value)
{
HitLimit=value;
};
int operator () (Results Rs)
{
if(Rs.Hits > this->HitLimit) abort;
}
};

Then you can use the callback as:

MyFunctor MyFunction(10);
MyObject.MyMethod(MyFunction);

Using a property has the advantage the it makes clear what is being set e.g.

MyFunction.HitLimit=10;
MyObject.MyMethod(MyFunction);

There are lots of very clever and sophisticated uses of function objects. The sorts of things you need to keep in mind are that because a function object is just an object it can take part in inheritance, polymorphism and you can use templates to create generic functors.

However as with most of C++ just because it is possible doesn't means it is a good idea.

Try and keep things simple.



Last Updated ( Monday, 15 August 2011 )
 
 

   
RSS feed of all content
I Programmer - full contents
Copyright © 2014 i-programmer.info. All Rights Reserved.
Joomla! is Free Software released under the GNU/GPL License.