Boost logo

Boost Users :

From: Douglas Gregor (gregod_at_[hidden])
Date: 2001-12-14 16:50:20


On Friday 14 December 2001 03:06 pm, you wrote:
> Hello,
>
> I'm trying to explore the compose, bind, and mem_fn libraries. I
> used a "real" problem I'm having. Given a vector<Trade>, I want to
> gather a sum of the return values of Trade::volume().
[...]
> vector<Trade> li;
> // .....
> sum = accumulate_with_op(li.begin(),li.end(),0,mem_fun_ref
> (&Trade::volume))
>
> This gives me my sum pretty nicely, so I'm sort of happy... BUT...

Here are two ways to compute the sum without defining your own functions or
classes. Both methods use std::accumulate (which, of course, is what you're
trying to do), but the difference is in the way that Trade::volume() is
called.

The first code snippet uses Boost.Bind only. We essentially create a function
object that takes two arguments, x and y, and then performs the operation x +
y.Volume(). We get '+' by using the standard library's plus<int>, and we use
the fact that bind is composable to call Volume on the second argument. The
code is thus:

std::accumulate(li.begin(), li.end(), 0,
                             boost::bind<int>(
                               std::plus<int>(),
                               _1,
                               boost::bind(&Trade::Volume, _2)));

The other option is philosophically different. Instead of transforming he
values as we add them, we instead transform the sequence we are adding using
the Boost Iterator Adaptors library. The transform_iterator adapts an
iterator by applying a function object to each element as it is dereferenced.
Therefore, the sequence that accumulate "sees" is the result of calling
Trade::Volume on each member of the underlying sequence. Here's the code:

std::accumulate(
              boost::make_transform_iterator(li.begin(),
                                             boost::mem_fn(&Trade::Volume)),
              boost::make_transform_iterator(li.end(),
                                             boost::mem_fn(&Trade::Volume)),
              0);

I consider this version better (philosphically) because the accumulation is
over things we can actually accumulate - integers. The transform_iterator
version is also more reusable code, because now you have the ability to
transform a sequence of Trade objects (or Trade object pointers - see the
documentation of mem_fn) into their corresponding trade volumes, and other
operations become simpler.

Code was tested under GCC 2.95.3, but I expect it will work for MSVC5.

        Doug


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net