The Same STL Algorithms -- Only Better

Vladimir Batov

Cleaner iteration with a better for_each.

If you are not using STL algorithms yet, you should be. In this article, I'll show how to enjoy using STL algorithms without being repelled by the seemingly unavoidable awkwardness of the standard member function adapters.

With all due respect towards STL algorithms, I am certainly sympathetic with those clinging to archaic, sub-optimal, and unsafe constructs such as:

for (vector::iterator it = v.begin();
     it != v.end(); ++it)
{
  it->do_something();
}
After all, from time to time, I myself am guilty of using such relics despite all the persuasive arguments from the masters [1]. Okay, okay, I am still working on it, although I'll step forward and say that true friends do not ask others to remember and maintain torturous constructs such as:
class Foo { ... void draw() const; };
extern void draw(const Foo&);

for_each(b, e, ptr_fun(draw));
for_each(b, e, mem_fun(&Foo::draw));
for_each(b, e, mem_fun_ref(&Foo::draw));
The first line passes a non-member function (draw) to an algorithm. The second line passes a member function (&Foo::draw) to an algorithm working on the sequence of pointers to objects. The third line passes a member function (&Foo::draw) to an algorithm working on the sequence of objects.

Confusing? It certainly is to me. If you found yourself grumbling about "if-this-if-that" scenarios and ptr_fun, mem_fun, and mem_fun_ref "beauties," you are not alone.

As Scott Meyers puts it, "They are unpleasant to type, annoying to read, and resistant to comprehension" (see [1], Item 41). I would most certainly prefer using STL algorithms in a friendlier way. For instance, without ptr_fun, mem_fun, and mem_fun_ref:

class Widget
{ ...
  void draw() const
  bool move();
};

extern void draw(const Widget&);

vector<Widget>  v1;
vector<Widget*> v2;

for_each(b1, e1, draw);
for_each(b1, e1, &Widget::draw);
for_each(b1, e1, &Widget::move);
for_each(b2, e2, &Widget::draw);
It turns out that getting rid of adapters is disappointingly easy to achieve. Listing 1 shows the extended aux::for_each interface consisting of three overloaded functions. The first function (lines 3-9) is the original std::for_each interface, which is still used with non-member functions (e.g., draw(const Widget&)) and function adapters (e.g., bind2nd). The other two functions (lines 11-33) are called respectively for const and non-const member functions (e.g., Widget::draw). They merely call the standard for_each algorithm with an appropriate functor object (lines 20 and 32). In the std namespace, you have to call mem_fun "convenience" functions to create those functors themselves. The following code shows the guts of the std::mem_fun declared in <functional>.
template <class R, class T>
mem_fun_t<R, T>
mem_fun(R (T::*func)())
{
  return mem_fun_t<R, T>(func);
}
template <class R, class T>
const_mem_fun_t<R, T>
mem_fun(R (T::*func)() const)
{
  return const_mem_fun_t<R, T>(func);
}
As aux::for_each functions create appropriate functors directly, in the aux namespace, you do not need mem_fun function adapters. You might have already guessed it -- you do not need mem_fun_ref either. Those adapters are the same as mem_fun, but they return functors of the mem_fun_ref_t and const_mem_fun_ref_t types. (If you stumbled on these types and your eyes refused to read them properly, they have _ref_t at the end.) The std::mem_fun_t and std::mem_fun_ref_t look very much alike:
// Simplified and beautified versions
// of the standard functors.

template <class Return, class Type>
class mem_fun_t
{
  typedef Return (Type::*Func)();

  public:

  explicit mem_fun_t(Func func)
  : func_(func) {}
   
  Return operator()(Type* obj) const
  {
    return (obj->*func_)();
  }
  private: Func func_;
};

template <class Return, class Type>
class mem_fun_ref_t
{
  typedef Return (Type::*Func)();

  public:

  explicit mem_fun_t(Func func)
  : func_(func) {}
   
  Return operator()(Type& obj) const
  {
    return (obj.*func_)();
  }
  private: Func func_;
};
The only differences are that the operator functions accept different types (pointers and references) and, consequently, use pointer or reference syntax to call a member function. Therefore, it appears only logical to merge the functionality into one aux::mem_fun_t class:
namespace aux {

template <class Return, class Type>
class mem_fun_t
{
  typedef Return (Type::*Func)();

  public:

  explicit mem_fun_t(Func func)
  : func_(func) {}
   
  Return operator()(Type* obj) const
  {
    return (obj->*func_)();
  }
  Return operator()(Type& obj) const
  {
    return (obj.*func_)();
  }
  private: Func func_;
};
}
Or if you prefer closer relations with the std::mem_fun_t cousin:
template <class R, class T>
struct mem_fun_t : std::mem_fun_t<R, T>
{
  typedef R (T::*Func)();
  typedef std::mem_fun_t<R, T> super;

  explicit mem_fun_t(Func func)
  : super(func) {}
   
  R operator()(T* obj) const
  {
    return super::operator()(obj);
  }
  R operator()(T& obj) const
  {
    return super::operator()(&obj);
  }
};
The aux::const_mem_fun_t is constructed in the same fashion. The complete source code is available at <www.cuj.com/code/>.

Note

[1] Scott Meyers. Effective STL (Addison-Wesley, 2001).

About the Author

With a beginning in machine code (yes, those zeros and ones) some 25 years ago, Vladimir Batov has been developing software ever since for nuclear power stations, air traffic control, military radars, many other things and just for fun. These days, apart from his interest in C++ and sofware design, he enjoys good books, tennis, sunsets over the bay in Melbourne, Australia, and digging in the sand on the beach with his daughter. He can be reached at vbatov@preston.net.