Top of document
©Copyright 1999 Rogue Wave Software

Function Objects

A function object is an instance of a class that defines the parenthesis operator as a member function. There are a number of situations where it is convenient to substitute function objects in place of functions. When a function object is used as a function, the parenthesis operator is invoked whenever the function is called.

To illustrate, consider the following class definition:

class biggerThanThree 
  {
    public:
    bool operator () (int val)
    { return val > 3; }
 };
 

If we create an instance of class biggerThanThree, every time we reference this object using the function call syntax, the parenthesis operator member function will be invoked. The next step is to generalize this class, by adding a constructor and a constant data field, which is set by the constructor.

class biggerThan {
    public:
       const int testValue;
       biggerThan (int x) : testValue(x) { }
 
       bool operator () (int val)
       { return val > testValue; }
 };
 

The result is a general "bigger than X" 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 will find the first value in a list that is larger than 12:

list<int>::iterator firstBig =
    find_if (aList.begin(), aList.end(), biggerThan(12));
 

Three of the most common reasons to use function objects in place of ordinary functions are to employ an existing function object provided by the standard library instead of a new function, to improve execution by using inline function calls, or to allow a function object to access or set state information that is held by an object. We will give examples of each.

The following table illustrates the function objects provided by the standard library.

Name
Implemented operations
arithmetic functions
plus
minus
times
divides
modulus
negate
addition x + y
subtraction x - y
multiplication x * y
division x / y
remainder x % y
negation - x
comparison functions
equal_to
not_equal_to
greater
less
greater_equal
less_equal
equality test x == y
inequality test x != y
greater comparison x > y
less-than comparison x < y
greater than or equal comparison x >= y
less than or equal comparison x <= y
logical functions
logical_and
logical_or
logical_not
logical conjunction x && y
logical disjunction x || y
logical negation ! x

Let's look at a couple of examples that show how these might be used. The first example uses plus() 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:

transform (listOne.begin(), listOne.end(), listTwo.begin(), 
    listOne.begin(), plus<int>() );
 

The second example negates every element in a vector of boolean values:

transform (aVec.begin(), aVec.end(), aVec.begin(), 
    logical_not<bool>() );
 
Location of the Class Definitions

The base classes used by the standard library in the definition of the functions shown in the preceding table are available for the creation of new unary and binary function objects. These base classes are defined as follows:

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 functions is found in Chapter 6. Here we want to take a binary function of type "Widget" and an argument of type integer, and compare the widget identification number against the integer value. A function to do this is written in the following manner:

struct WidgetTester : binary_function<Widget, int, bool> {
 public:
    bool operator () (const Widget & wid, int testid) const
       { return wid.id == testid; }
 };
 

A second reason to consider using function objects instead of functions is faster code. In many cases an invocation of a function object, such as the examples given in the calls on transform() presented earlier, can be expanded in-line, eliminating the overhead of a function call.

Using Function Objects to Store References

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 generate(). A generator is simply a function that returns a 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 standard library function generate() will initialize a vector of 20 elements with the values 1 through 20:

vector<int> aVec(20);
 generate (aVec.begin(), aVec.end(), iotaGen(1));
 

Top of document