Noeud:Function Adaptors, Noeud « Next »:, Noeud « Previous »:Some Predefined Function Objects, Noeud « Up »:Generic Algorithms and Function Objects



Function Adaptors

Function adpators are function objects that enable us to pass in other function objects as arguments, and there are a few worth mentioning that are extremely useful. The first set enable us to bind different arguments passed in (bind1st and bind2nd) to operations; the second set let us pass member functions as arguments (mem_fun and mem_fun_ref). Let's look at them each in turn.

Recall from Function Objects - in a Nutshell in function2.cc we defined our own with_each method that took an additional parameter of type T so that we could pass in the value to make a comparison against the elements of the container, using the greater function object. The reason we did this was because greater is a binary function object, and it needs a second value to compare against, and so we provided it by supplying it a parameter. But the only way of doing this would be to modify the with_each method to cope with the extra parameter, which is what we did. But wait - look what happens if we change with_each as follows:

     /* function3.cc
      * Compiled using g++ function3.cc -o function3 */
     #include <vector>
     #include <functional>
     
     /* Define our own method that uses a unary function 'fn' on
      * a range of elements: */
     template <class InputIterator, class UnaryFn, class Message>
     void with_each(InputIterator beg, InputIterator end, UnaryFn fn,
     	       Message msg)
     {
       for( ; beg != end; ++beg)
         if (fn(*beg))
           cout << msg << *beg << endl;
     }
     
     int main()
     {
       std::vector<int> v;
       v.push_back(10);
       v.push_back(2);
       v.push_back(14);
       with_each(v.begin(), v.end(),
     	    bind1st(greater<int>(), 7), "7 is greater than ");
       return 0;
     }
     
     Example 3.17: function3.cc
     

This may seem esoteric, but what's actually happening is bind1st is transforming greater into a unary function object. The effect of bind1st(op, val) is to turn op into a unary function object such that op will work with the parameters op(val, param). Thus, val will take on the value 7, and param will be whatever value we're working with inside the body of the with_each method, in other words the value held in *beg. Thus, when fn(*beg) is called in the body of with_each, we're calling greater with one argument (because bind1st turned it into a unary function), and the condition if (fn(*beg)) yields true for all values that are greater than 7.

bind2nd is similar except that it binds its second parameter to be the first argument to be used in function fn. In other words, it transforms bind2nd(op, val) into op(param, val).

Lets now look at mem_fun_ref and mem_fun.

The easiest way to describe mem_fun_ref is to revisit the Address class. First, recall from Vector how we printed Address objects:

       /* Declare an iterator to work with: */
       std::vector<Address>::iterator pos;
       /* Loop through the vector printing out elements: */
       cout << "First iteration" << endl;
       for (pos=v.begin(); pos<v.end(); ++pos)
         {
           pos->print();
         }
     

There's an easier way to do this, using mem_fun_ref. In the following code, we're actually going to use with_each again, which may seem counter-intuitive; well, it is if every time we're going to make function object calls to iterate a collection of objects we have to define code to do so. with_each is just a stub for a generic algorithm called for_each, which we'll be looking at soon. Let's pass print to mem_fun_ref as we traverse through a vector of Address objects:

     /* function4.cc
        Compiled using g++ function4.cc Address.cc -o function4 */
     #include <functional>
     #include <vector>
     #include "AddressRepository.hh"
     
     /* Define our own method that uses a unary function 'fn' on
      * a range of elements: */
     template <class InputIterator, class UnaryFn>
     void with_each(InputIterator beg, InputIterator end, UnaryFn fn)
     {
       for( ; beg != end; ++beg)
         fn(*beg);
     }
     int main()
     {
       vector<Address> v;
       /* Add all of the address objects to the vector: */
       v.push_back(addr1);
       v.push_back(addr2);
       v.push_back(addr3);
       v.push_back(addr4);
       v.push_back(addr5);
       /* Now call 'print' with each element, passing it by reference: */
       with_each(v.begin(), v.end(), mem_fun_ref(&Address::print));
       exit(0);
     }
     
     Example 3.18: function4.cc
     

The output is obvious: it prints out the list of Address objects. This is an extremely useful function object, because otherwise we'd have to define our own function object (called fun_ob_print_address within the Address class for example) which would do this work for us with the with_each algorithm, if we weren't happy with the pos->print() way of doing things. This adds extra code and is uneccessary if we can use mem_fun_ref.

mem_fun isn't too different; but instead of using a reference, mem_fun uses a pointer to an element.

Note that with both mem_fun and mem_fun_ref, the called member functions must be constant member function, otherwise a compile error will result.

These function adaptors are summarised in Function Adaptor Reference.