A function object is an object to which the function call operator can be applied. Typically, it is a class that defines the function call operator (operator()()) as a member function. When a function object is used as a function, the function call operator is invoked whenever the function is called. Consider the following class definition:
class biggerThanThree { public: bool operator()(int val) const { return val > 3; } };
If we create an instance of class biggerThanThree, every time we reference this object using the function call syntax, the function call operator member function is invoked. To generalize this class, we add a constructor and a constant data member, which is set by the constructor:
class biggerThan { public: const int testValue; biggerThan(int x) : testValue(x) { } bool operator()(int val) const { return val > testValue; } };
The result is a general biggerthanX function, where the value of X is determined when we create an instance of the class. We can do so, for example, as an argument to one of the generic functions that require a predicate. In this manner the following code finds the first value in a list that is larger than 12:
std::list<int>::iterator firstBig = std::find_if(aList.begin(), aList.end(), biggerThan(12));
There are a number of situations where it is convenient to substitute function objects in place of functions: to use an existing function object provided by the C++ Standard Library instead of a new function; to improve execution by using inline function calls; and to allow a function object to access or set state information that is held by an object. Let's deal with each of these in the next three sections.
Table 5 illustrates the function objects provided by the C++ Standard Library.
Let's look at a couple of examples that show how these might be used. The first example uses std::plus<int>() to compute the by-element addition of two lists of integer values, placing the result back into the first list. This can be performed by the following code:
std::transform(listOne.begin(), listOne.end(), listTwo.begin(), listOne.begin(), std::plus<int>() );
The second example negates every element in a vector of boolean values:
std::transform(aVec.begin(), aVec.end(), aVec.begin(), std::logical_not<bool>() );
The base class templates used by the C++ Standard Library to define the functions in Table 5 are also available for creating new unary and binary function objects. The class templates unary_function and binary_function are defined in the header <functional>.
The base classes are defined as follows:
namespace std { template <class Arg, class Result> struct unary_function { typedef Arg argument_type; typedef Result result_type; }; template <class Arg1, class Arg2, class Result> struct binary_function { typedef Arg1 first_argument_type; typedef Arg2 second_argument_type; typedef Result result_type; }; }
An example of the use of these templates is found in Section 6.3. There we want to take a binary function of type Widget and an argument of type int, and compare the widget identification number against the integer value. A function to do this is written in the following manner:
struct WidgetTester : std::binary_function<Widget, int, bool>{ bool operator() (const Widget& wid, int testid) const { return wid.id == testid; } };
The importance of inheritance from one of the two base class templates becomes apparent when elementary function objects are composed to form complex expressions using negators and binders, which are explained in Section 3.5.
A second reason to consider using function objects instead of functions is faster code. The difference between a function and an object of a class that defines the member operator()() is that functions are converted to pointers when passed as arguments to other functions, thus incurring the overhead of a function call even if they are declared inline. In many cases an invocation of a function object, as in the examples on std::transform() in Section 3.2.2.1, can be expanded in-line, eliminating the overhead of a function call.
The third major reason to use a function object in place of a function is when each invocation of the function must remember some state set by earlier invocations. An example of this occurs in the creation of a generator, to be used with the generic algorithm std::generate(). A generator is simply a function object that takes no arguments and returns a new (and possibly different) value each time it is invoked. The most commonly used form of generator is a random number generator, but there are other uses for the concept. A sequence generator simply returns the values of an increasing sequence of natural numbers (1, 2, 3, 4 and so on). We can call this object iotaGen after the similar operation in the programming language APL, and define it as follows:
class iotaGen { public: iotaGen (int start = 0) : current(start) { } int operator() () { return current++; } private: int current; };
An iota object maintains a current value, which can be set by the constructor, or defaults to zero. Each time the function-call operator is invoked, the current value is returned, and also incremented. Using this object, the following call on the C++ Standard Library function std::generate() initializes a vector of 20 elements with the values 1 through 20:
std::vector<int> aVec(20); std::generate(aVec.begin(), aVec.end(), iotaGen(1));
A more complex example of using a function object occurs in the radix sorting example program, which is given as an example of using the list datatype in Section 6.3. In this program references are initialized in the function object, so that during the sequence of invocations the function object can access and modify local values in the calling program.