Function Objects
Many STL algorithms allow you to pass a function pointer into the algorithm to help the algorithm perform its task. For example, the binary_search algorithm that we discussed in Section 23.5.6 is overloaded with a version that requires as its fourth parameter a pointer to a function that takes two arguments and returns a bool value. The binary_search algorithm uses this function to compare the search key to an element in the collection. The function returns TRue if the search key and element being compared are equal; otherwise, the function returns false. This enables binary_search to search a collection of elements for which the element type does not provide an overloaded equality == operator.
STL's designers made the algorithms more flexible by allowing any algorithm that can receive a function pointer to receive an object of a class that overloads the parentheses operator with a function named operator(), provided that the overloaded operator meets the requirements of the algorithmin the case of binary_search, it must receive two arguments and return a bool. An object of such a class is known as a function object and can be used syntactically and semantically like a function or function pointerthe overloaded parentheses operator is invoked by using a function object's name followed by parentheses containing the arguments to the function.
Function objects provide several advantages over function pointers. Since function objects are commonly implemented as class templates that are included into each source code file that uses them, the compiler can inline an overloaded operator() to improve performance. Also, since they are objects of classes, function objects can have data members that operator() can use to perform its task.
Predefined Function Objects of the Standard Template Library
Many predefined function objects can be found in the header . Figure 23.41 lists several of the STL function objects, which are all implemented as class templates. We used the function object less< T > in the set, multiset and priority_queue examples, to specify the sorting order for elements in a container.
STL function objects |
Type |
---|---|
divides< T > |
arithmetic |
equal_to< T > |
relational |
greater< T > |
relational |
greater_equal< T > |
relational |
less< T > |
relational |
less_equal< T > |
relational |
logical_and< T > |
logical |
logical_not< T > |
logical |
logical_or< T > |
logical |
minus< T > |
arithmetic |
modulus< T > |
arithmetic |
negate< T > |
arithmetic |
not_equal_to< T > |
relational |
plus< T > |
arithmetic |
multiplies< T > |
arithmetic |
Using the STL Accumulate Algorithm
Figure 23.42 demonstrates the accumulate numeric algorithm (discussed in Fig. 23.30) to calculate the sum of the squares of the elements in a vector. The fourth argument to accumulate is a binary function object (that is, a function object for which operator() takes two arguments) or a function pointer to a binary function (that is, a function that takes two arguments). Function accumulate is demonstrated twiceonce with a function pointer and once with a function object.
Figure 23.42. Binary function object.
(This item is displayed on pages 1188 - 1189 in the print version)
1 // Fig. 23.42: Fig23_42.cpp 2 // Demonstrating function objects. 3 #include 4 using std::cout; 5 using std::endl; 6 7 #include // vector class-template definition 8 #include // copy algorithm 9 #include // accumulate algorithm 10 #include // binary_function definition 11 #include // ostream_iterator 12 13 // binary function adds square of its second argument and the 14 // running total in its first argument, then returns the sum 15 int sumSquares( int total, int value ) 16 { 17 return total + value * value; 18 } // end function sumSquares 19 20 // binary function class template defines overloaded operator() 21 // that adds the square of its second argument and running 22 // total in its first argument, then returns sum 23 template< typename T > 24 class SumSquaresClass : public std::binary_function< T, T, T > 25 { 26 public: 27 // add square of value to total and return result 28 T operator()( const T &total, const T &value ) 29 { 30 return total + value * value; 31 } // end function operator() 32 }; // end class SumSquaresClass 33 34 int main() 35 { 36 const int SIZE = 10; 37 int array[ SIZE ] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 38 std::vector< int > integers( array, array + SIZE ); // copy of array 39 std::ostream_iterator< int > output( cout, " " ); 40 int result; 41 42 cout << "vector integers contains: "; 43 std::copy( integers.begin(), integers.end(), output ); 44 45 // calculate sum of squares of elements of vector integers 46 // using binary function sumSquares 47 result = std::accumulate( integers.begin(), integers.end(), 48 0, sumSquares ); 49 50 cout << " Sum of squares of elements in integers using " 51 << "binary function sumSquares: " << result; 52 53 // calculate sum of squares of elements of vector integers 54 // using binary function object 55 result = std::accumulate( integers.begin(), integers.end(), 56 0, SumSquaresClass< int >() ); 57 58 cout << " Sum of squares of elements in integers using " 59 << "binary function object of type " 60 << "SumSquaresClass< int >: " << result << endl; 61 return 0; 62 } // end main
|
Lines 1518 define a function sumSquares that squares its second argument value, adds that square and its first argument total and returns the sum. Function accumulate will pass each of the elements of the sequence over which it iterates as the second argument to sumSquares in the example. On the first call to sumSquares, the first argument will be the initial value of the total (which is supplied as the third argument to accumulate; 0 in this program). All subsequent calls to sumSquares receive as the first argument the running sum returned by the previous call to sumSquares. When accumulate completes, it returns the sum of the squares of all the elements in the sequence.
Lines 2332 define a class SumSquaresClass that inherits from the class template binary_function (in header file )an empty base class for creating function objects in which operator receives two parameters and returns a value. Class binary_function accepts three type parameters that represent the types of the first argument, second argument and return value of operator, respectively. In this example, the type of these parameters is T (line 24). On the first call to the function object, the first argument will be the initial value of the total (which is supplied as the third argument to accumulate: 0 in this program) and the second argument will be the first element in vector integers. All subsequent calls to operator receive as the first argument the result returned by the previous call to the function object, and the second argument will be the next element in the vector. When accumulate completes, it returns the sum of the squares of all the elements in the vector.
Lines 4748 call function accumulate with a pointer to function sumSquares as its last argument.
The statement at lines 5556 calls function accumulate with an object of class SumSquaresClass as the last argument. The expression SumSquaresClass< int >() creates an instance of class SumSquaresClass (a function object) that is passed to accumulate, which sends the object the message (invokes the function) operator. The statement could be written as two separate statements, as follows:
SumSquaresClass< int > sumSquaresObject; result = std::accumulate( integers.begin(), integers.end(), 0, sumSquaresObject );
The first line defines an object of class SumSquaresClass. That object is then passed to function accumulate.