Step 2: Using for_each()
The Standard Library defines an algorithm std::for_each(), which is ideal for this purpose. Not only does it eliminate iterator type dependencies, it also takes a parameterized function argument that can be a real function, a member function, or a function object. You can thus rewrite the previous loop like this, at least theoretically:
#include <algorithm> //for for_each()
std::for_each (vt.begin(), vt.end(), &Task::show_pid);
This implementation is simpler, more readable, and iterator-independent. Alas, it won't compile. As previously explained, passing a member function's address isn't enough; you can't invoke it without specifying an object. Worse, the generic design of for_each() doesn't allow you to pass a fourth argument.
| |
 |
Figure 2: Here is the output of this for_each() call.
|
Step 3: Using a Function Adapter
Fortunately, you don't really need a fourth argument because the member function show_pid() should be called for every object in the range vt.begin() vt.end(). But how do you tell for_each() to do this?
The Standard Library also defines a set of function adapters that bind a member function to an object and return a matching function object. For example, std::mem_fun_ref() takes a member function's address and binds it to an object's reference, which is exactly what you need:
std::for_each (vt.begin(),
vt.end(),
std::mem_fun_ref(&Task::show_pid));
mem_fun_ref() function binds &Task::show_pid to a reference to Task. The effect is the same as calling show_pid() for every Task object in the sequence vt.begin() vt.end().
Figure 2 shows the output of this for_each() call.
Notice that the results of this example and the previous for-loop are identical. The benefit of using for_each() is maintenance ease and improved readability.