[Dev] STL for_each underwhelms me
M. Mueller (bhu5nji)
dev@trilug.org
Mon, 11 Feb 2002 16:53:57 -0500
On Monday 11 February 2002 03:35 pm, you wrote:
> On Mon, 2002-02-11 at 15:07, M. Mueller (bhu5nji) wrote:
> > > What specifically do you want for_each to do for you?
> >
> > I have a map of entries where the key is a transaction ID and the entries
> > describe a socket connection and related query, timestamp, state,
> > response, etc. For each entry, do a non-blocking read on stream socket,
> > check to see that the request is fully formed and if so, change the state
> > to re-form the query and forward. This is part of a proxy server.
> >
> > I tried : for_each(xmap.begin(), xmap,end(), clientRead);
> >
> > clientRead is a member of proxy server class object.
> >
> > Heeding the compiler (gcc 3.0) error I changed to:
> > or_each(xmap.begin(), xmap,end(), &classname::clientRead);
> >
> > Still get "out of scope" error.
>
> You're getting an 'out of scope' error probably because clientRead
> is not a static function. Basically, for_each needs a regular function,
> *or* a function object *or* a function adaptor. What you could do
> is write a function adaptor (sometimes called a functor, I believe)
So that's what a functor is. Function adapter is a better name - by far.
> that you pass your proxy object to and it acts as a shim, transfering
> for_each's calls to the correct method. For example
Thank you. Shim is good.
>
> struct clientReadAdaptor {
>
> clientReadAdaptor(classtypename *classname) : myclass(classname) {}
>
> void operator() (xmaptypename *xmap) { myclass->clientRead(xmap); }
>
> private:
> classtypename *myclass;
> };
>
> Then you could just do
>
> for_each(xmap.begin(), xmap.end(), clientReadAdaptor(&classname));
>
> > for_each likes functions, not methods, as far as I can tell. I assume
> > the compiler needs to be "tricked" into thinking the method is a
> > function.
>
> Not tricked. Told how to call it. It can't call the method because it
> doesn't know anything about the classes vtable (because it doesn't
> know anything about the class).
Function is an address and method is an offset from the base of the table?
>
> > If that analysis is correct, then I have to wonder about writing "tricky"
> > code.
>
> You just have to have the right mindset. Oh, and understand about
> the difference between calling a function and calling a method.
>
> > This example seems like it uses operator overloading to make for_each do
> > something more complicated that it would otherwise be capable of. This
> > does not seem like a use of operator overloading "to allow a programmer
> > to provide a more conventional and convenient notation for manipulating
> > class objects". (Quote from 7.1 C++ by Stroustrup.)
> >
> > The example seems to be a template. So now it has the advantage of being
> > generic. On the other hand, the number of test cases needed has just
> > gone up dramatically.
> >
> > -------------------------------------------------------------------------
> >-
> >
> > template<class T> struct print : public unary_function<T, void>
> > {
> > print(ostream& out) : os(out), count(0) {}
> > void operator() (T x) { os << x << ' '; ++count; }
> > ostream& os;
> > int count;
> > };
> >
> > int main()
> > {
> > int A[] = {1, 4, 2, 8, 5, 7};
> > const int N = sizeof(A) / sizeof(int);
> >
> > print<int> P = for_each(A, A + N, print<int>(cout));
> >
> > // I find "print<int>" and "print<int>(cout)" difficult to read - I have
> > no // familiarity with "Z" and "Z(func)" being meaningful is other
> > contexts. // When the '+' is overloaded for strings, I find string1 +
> > string2 easy to // understand.
> >
> > cout << endl << P.count << " objects printed." << endl;
> > }
> >
> > -------------------------------------------------------------------------
> >-- An alternative that seems quite a bit easier to understand.
> >
> > int main()
> > {
> > int A[] = {1, 4, 2, 8, 5, 7};
> > const int N = sizeof(A) / sizeof(int);
> >
> > int count=0;
> > for (int i=0; i < N; i++)
> > {
> > cout << A[i] << ' ';
> > count++;
> > }
> > cout << endl << count << " objects printed" << endl;
> > }
>
> Easier to understand, maybe, but what if you have to do the same thing
> over 100 times? 1000 times? What if you don't do it the same way
> each time? How about the nubmer of test cases then?
>
> > I can't help feeling that the operator overloading used with for_each is
> > a sophisticated way to get more stuff into a unary function. I have no
> > problem with for_each as long as simple unary functions are used.
> > Introducing operator overloading to squeeze more functionality into the
> > limits of the unary function results in complicated code. Maybe the
> > complicated code is more versatile, but that means there are more test
> > cases to perform. Operator overloading with for_each also yields terse
> > code, which is esthetically pleasing. The esthetics are lost on myself
> > after I've gazed at the well-crafted code for an hour and I am still not
> > sure of what it does.
>
> It does get easier to understand after you adjust how you think about
> the code. And really, it's just another way of doing the same thing.
> Don't think of it as "sophisticated", just think of it as something
> different. C++ is inherently different than C and without realizing
> this, you can't really make use of the power C++ provides you.
I am truly amazed how the containers in STL have so rapidly changed that way
I approach design. I've OO-ing things in my product (www.signalnetware.com)
since last summer and I've had some handsome payoffs for the work. I can
sense their is more value to be had. I really got frustrated with the
for_each algorithm, though.
>
> > I'm going to keep studying this operator overloading subject. I havn't
> > used it much.
>
> Perhaps it would help instead of calling it "operator overloading"
> to call it a function adapter.
"Function adapter" helps quite a bit.
What do you do if you want to plug
> a 3 prog electrical plug in a 2 prog socket? You get an adapter.
> That's all these object are doing. The analogy is not perfect,
> however, because going from 3 prong to 2 prong you lose something.
> By using function adapters, I personally believe you gain a lot
> over a simple unary function.
>
> Tanner