Functors (Function Objects)

What is a functor?

A functor, also known as a function object, is an object that is able to be called as if it were a function. In C++, we do this by overloading the function call operator -- operator() -- which is the one special operator that does not fit into the "binary" or "unary" classification of operators. This operator can take any parameter list that a normal function can.

Here is an example of such a class:

class Functor1
{
public:
    int operator()(int a, int b)
    {
        return a < b;
    }
};
Note that this is a class with this operator overload as a member function:
  int operator()(int a, int b);
It's definition is set up to return a true (or 1) if a < b is true, or to return a false (0) otherwise.

If this were a named function (suppose a function called Func), then we would call it for an object like this:

   Functor1 f;			// object of the class type
   cout << f.Func(4, 7);	// call the function with two integer params
But of course, the name is NOT Func, the name is operator(), which gives us:
   Functor1 f;			// object of the class type
   cout << f.operator()(4, 7);	// call the function with two integer params
This notation is a bit tedious and unnecessary. Instead, the function call operator allows the calling object to act as the function name -- the following code is equivalent to the above:
   Functor1 f;			// object of the class type
   cout << f(4, 7);		// call the function with two integer params
Look at this example link with two functor classes, each with a different operator() inside:

The Strategy Pattern

So what is the purpose of using a functor? It helps us implement a common software engineering design pattern used in coding -- the strategy pattern.

The strategy pattern is the idea of passing a function into a function -- i.e. a pluggable algorithm.

Example

Consider a common algorithm to print the contents of an integer array, formatted as a comma-separated list of data inside of set braces -- we can write that easily in a function:

void PrintArray(const int* array, unsigned int size)
{
   bool first = true;
   cout << "{";
   for (unsigned int i = 0; i < size; i++)
   {
      if (!first)
	cout << ", ";
      cout << array[i];
      first = false;
   }   
   cout << "}";
}
Now, what if we wanted a similar function, but one that would print out only the values in the array that were positive numbers? Then we would need to write another version of the function, which would be similar, but slightly different, with an added condition:
void PrintArrayPostives(const int* array, unsigned int size)
{
   bool first = true;
   cout << "{";
   for (unsigned int i = 0; i < size; i++)
   {
      if (array[i] > 0)		// IF the value is positive
      {				//  then print it
         if (!first)
	    cout << ", ";
         cout << array[i];
         first = false;
      }
   }   
   cout << "}";
}
And if we wanted a function that printed only the ODD numbers from the array, we have yet another function, with almost the same code. ALMOST -- with the only difference being the condition for printing
void PrintArrayOdds(const int* array, unsigned int size)
{
   bool first = true;
   cout << "{";
   for (unsigned int i = 0; i < size; i++)
   {
      if (array[i] % 2 != 0)    // IF the value is ODD
      {				//  then print it
         if (!first)
	    cout << ", ";
         cout << array[i];
         first = false;
      }
   }   
   cout << "}";
}
We could do this with a variety of conditions. Print only the even numbers. Print only the negative numbers. Print only the numbers that are divisible by 3. Etc.

But does each one really require the writing of a totally separate function, which is identical to the others and differs only in the conditions? Here's an example illustrating a number of such functions. Notice that all of these functions have ALMOST the same code -- only very slight differences in each.

Writing code via brute-force copy/paste is never a very good idea. If you find yourself writing the same code multiple times, even with slight variations, there's going to be a way to simplify!

Passing the condition as a parameter

To write the one function that can do all of these printouts, we need to pass in the condition -- the only way these functions differ -- as a parameter.

This can be done with function pointers, which are ugly bit of old C syntax. But it's much nicer to do it with functors. Remember that objects are variables, and we pass those into functions all the time. But objects can also carry member functions inside. So this is how we pass a function into another function -- wrap the function into an object and send it that way!

This is a template function we can use to replace all of the other brute-force ones:

template <typename Condition>
void PrintArray(const int* array, unsigned int size, Condition cond)
{
   bool first = true;
   cout << "{";
   for (unsigned int i = 0; i < size; i++)
   {
      if (cond(array[i]))       // if the condition is true  
      {                         // then print the item
         if (!first)
            cout << ", ";
         cout << array[i];
         first = false;
      }
   }           
   cout << "}\n";
}
Note that the third parameter is a template type called Condition, and any object type can be passed here. We want to pass objects that will act as functors, carrying an operator() function inside. Then we will use the parameter cond AS a function call itself, to test a true/false condition on the array item:
  if (cond(array[i]))
Whenever this is true, we print.

To use this template function, we have to create appropriate conditions, which are classes with the operator() function defined to be the condition check, returning a true/false. Here is a file with some condition rules:

For example, one of the classes setting up a condition is:
class IsPos
{
public:
   bool operator() (int x)      
   {   return (x > 0);   }
};
To use this, create an object of type IsPos, and then pass into the print function as the 3rd parameter:
  IsPos obj;
  PrintArray(list, 15, obj);
OR, just call the default constructor for IsPos explicitly, to build an R-value object with no name:
  PrintArray(list, 15, IsPos() );	// passes in a nameless IsPos object
Here is a full code example with a main() that is equivalent to the bad example earlier. This one uses the templated PrintArray function with the condition parameter to handle ALL of the possible outputs, using various conditions found in the conditions.h file.

One more set of code examples

This example illustrates using function objects to write a generic sort function, which can sort strings by various criteria, without having to write the same sort algorithm over and over and over. In this example, the files are: