I l@ve RuBoard Previous Section Next Section

4.9 Implementing a Function Object

In Section 3.6, we looked at the predefined function objects of the standard library. In this section, we look at how to implement our own function objects. A function object is a class that provides an overloaded instance of the function call operator.

When the compiler encounters what appears to be a function call, such as



lt( ival ); 

lt can be the name of a function, a pointer to function, or an object of a class that has provided an instance of the function call operator. If lt is a class object, the compiler internally transforms the statement as follows:



lt.operator()( ival ); // internal transformation 

The function call operator can take any number of parameters: none, one, two, and so on. It is used, for example, to support multidimensional subscripting of a Matrix class because the actual subscript operator is limited to accepting one parameter.

Let's implement an overloaded instance of the call operator to test whether a value passed to it is less than some other value. We'll call the class LessThan. Each object must be initialized with a value against which to compare. In addition, we support read and write access of that value. Here's our implementation:



class LessThan { 


public: 


   LessThan( int val ) : _val( val ){} 


   int  comp_val() const    { return _val; } 


   void comp_val( int nval ){ _val = nval; } 





   bool operator()( int value ) const; 





private: 


   int _val; 


}; 

The implementation of the function call operator looks like this:



inline bool LessThan:: 


operator()( int value ) const { return value < _val; } 

We can explicitly define a LessThan class object in the same way as any other class object:



LessThan lt10( 10 ); 

We invoke the overloaded call operator function by applying the call operator (()) to the class object. For example,



int count_less_than( const vector<int> &vec, int comp ) 


{ 


   LessThan lt( comp ); 





   int count = 0; 


   for ( int ix = 0; ix < vec.size(); ++ix ) 


         if ( lt( vec[ ix ] )) 


              ++count; 





   return count; 


} 

More typically, we pass a function object as an argument to a generic algorithm:



void print_less_than( const vector<int> &vec, 


                      int comp, ostream &os = cout ) 


{ 


   LessThan lt( comp ); 


   vector<int>::const_iterator iter = vec.begin(); 


   vector<int>::const_iterator it_end = vec.end(); 





   os << "elements less than " << lt.comp_val() << endl; 


   while (( iter = find_if( iter, it_end, lt )) != it_end ) 


   { 


          os << *iter << ' '; 


          ++iter; 


   } 


} 

Here's a small program to exercise these two functions:



int main() 


{ 


   int ia[16] = { 17, 12, 44, 9, 18, 45, 6, 14, 


                  23, 67, 9, 0, 27, 55, 8, 16 }; 


   vector<int> vec( ia, ia+16 ); 


   int comp_val = 20; 





   cout << "Number of elements less than " 


        << comp_val << " are " 


        << count_less_than( vec, comp_val ) << endl; 


   print_less_than( vec, comp_val ); 


} 

When compiled and executed, the program generates the following output:



Number of elements less than 20 are 10 


elements less than 20 


17 12 9 18 6 14 9 0 8 16 

Appendix B provides additional examples of function object definitions.

    I l@ve RuBoard Previous Section Next Section