[Dev] STL for_each underwhelms me
M. Mueller (bhu5nji)
dev@trilug.org
Mon, 11 Feb 2002 16:07:02 -0500
>
> Perhaps it would help if you would explain a bit more about
> what you're trying to do, and why a unary function won't work
> for you? Without knowing that, however, you probably want to
> look around for documentation about a "function object" which
> is an object designed to look like a function but that can
> hold state.
Nice description. That's one light. The David Musser STL Tutorial only
talks about functions, never about function objects that have state. So, now
I can envision that the function object is "sent in" to the for_each
algorithm.
>
> Say, for example, you want to take a vector of ints and calculate
> it's mean value. With a plain old for, you could loop through
> each element of the vector and calculate the sum and finally
> divide by the number of elements. With for_each, however, you
> could do it like this:
>
> // function object to process the mean value
> class MeanValue {
> private:
> long num; // number of elements
> long sum; // sum of all elements
> public:
> // Constructor
> MeanValue() : num(0), sum(0) {}
>
> // function call
> void operator() (int elem) {
> ++num; // increment count
> sum += elem;
> }
>
> // return mean value
> double value () {
> return static_cast<double>(sum) / static_cast<double>(num);
> }
> };
>
> int main(void)
> {
> vector<int> coll;
>
> // insert elements from 1 to 8
> for (int i = 1; i <=8; ++i) {
> coll.push_back(i);
> }
>
> // Process and print mean value
> MeanValue mv = for_each(col.begin(), coll.end(), MeanValue());
>
> cout << "mean value: " << mv.value() << endl;
>
> return 0;
> }
>
> Note that this also shows another feature of for_each, it
> returns the (modified) function object passed to it. As far
> as I know, this is the only STL algorithm that does that.
> I believe this is an example of what you called
> "class_with_overloaded_operators".
>
> Your "magically_transformed_things_that_appear_to_be_UF" are better
> know as "function adapters". basically, they're functions that
> you can pass a second (or first) argument to them and they'll
> handle the fact that for_each only expects a unary function.
> So, if you wanted to multiply each element by a number, you'd
> need a function adapter that took the number you wanted to
> multiply by and provided a function for for_each to call.
This is where I cannot clearly see the benefits of using for_each. I am
havine the hardest time learning why I would choose to overload operators to
create a way to squeeze in two parms where the design called for one. I keep
hearing the cries of those following my code, "what the heck is going on
here?". Why not choose (what I think is) the simpler way - write a function
or method and call it in a for loop? Perhaps this is just a more explicit
way. It is not obvious to me that using the for_each will produce better
performance that using the for-loop.
I am saying that STL does not create simpler code. In general, I am very
pleased with STL. I practically think in sets and maps these days. I'll
never write another linked-list.
I suspect one of my problems with for_each is a poor understanding of
operator overloading, especially for the "function call"
>
> Also, note that if you're trying to modify a bunch of elements,
> transform is often a better function to use. The difference
> between tranform and for_each is that for_each expects a
> unary function that returns void, so if you want to modify
> the elements, you need to pass them by reference. Transform,
> on the other hand, takes a unary operation that returns
> a value. This value replaces the previous value in that
> position of the container. So, if you wanted to square a
> bunch of elements, you could do either this:
>
> void square(int &elem) { elem = elem * elem; }
> for_each(coll.begin(), coll.end() square);
>
> or this:
>
> int square(int elem) { return elem * elem; }
> transform(coll.begin(), coll.end(), // source range
> coll.begin(), // destination range
> square); // operation.
The code here is quite readable.
>
> But, once again, because C++ offers lots of ways to do things,
> it would help if we knew just what it was you're doing. :-)
See my reply to Brent Verner.
>
> Tanner