[Dev] STL for_each underwhelms me

Tanner Lovelace dev@trilug.org
11 Feb 2002 15:35:20 -0500


--=-NNbX4oZ3cXNlugFLVnyZ
Content-Type: text/plain
Content-Transfer-Encoding: quoted-printable

On Mon, 2002-02-11 at 15:07, M. Mueller (bhu5nji) wrote:
>=20
> > What specifically do you want for_each to do for you?
>=20
> I have a map of entries where the key is a transaction ID and the entries=
=20
> describe a socket connection and related query, timestamp, state, respons=
e,=20
> etc.  For each entry, do a non-blocking read on stream socket, check to s=
ee=20
> that the request is fully formed and if so, change the state to re-form t=
he=20
> query and forward.  This is part of a proxy server.
>=20
> I tried : for_each(xmap.begin(), xmap,end(), clientRead);
>=20
> clientRead is a member of proxy server class object.
>=20
> Heeding the compiler (gcc 3.0) error I changed to:=20
> or_each(xmap.begin(), xmap,end(), &classname::clientRead);
>=20
> Still get "out of scope" error.
>=20

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)
that you pass your proxy object to and it acts as a shim, transfering
for_each's calls to the correct method.  For example

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 th=
e=20
> 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).
=20
> If that analysis is correct, then I have to wonder about writing "tricky"=
=20
> code.
>=20

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=20
> something more complicated that it would otherwise be capable of.  This d=
oes=20
> not seem like a use of operator overloading "to allow a programmer to pro=
vide=20
> a more conventional and convenient notation for manipulating class object=
s". =20
> (Quote from 7.1 C++ by Stroustrup.)
>=20
> The example seems to be a template.  So now it has the advantage of being=
=20
> generic.  On the other hand, the number of test cases needed has just gon=
e up=20
> dramatically. =20
>=20
> -------------------------------------------------------------------------=
-
>=20
> 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;
> };
>=20
> int main()
> {
>   int A[] =3D {1, 4, 2, 8, 5, 7};
>   const int N =3D sizeof(A) / sizeof(int);
>=20
>   print<int> P =3D for_each(A, A + N, print<int>(cout));
>=20
> // 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.=
  =20
> // When the '+' is overloaded for strings, I find string1 + string2 easy =
to=20
> // understand.
>=20
>   cout << endl << P.count << " objects printed." << endl;
> }
>=20
> -------------------------------------------------------------------------=
--
> An alternative that seems quite a bit easier to understand.
>=20
> int main()
> {
>   int A[] =3D {1, 4, 2, 8, 5, 7};
>   const int N =3D sizeof(A) / sizeof(int);
>=20
>   int count=3D0;
>   for (int i=3D0; i < N; i++)=20
> 	{
> 	cout << A[i] << ' ';
> 	count++;
> 	}
>   cout << endl << count << " objects printed" << endl;
> }
>=20

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?
=20
> I can't help feeling that the operator overloading used with for_each is =
a=20
> sophisticated way to get more stuff into a unary function.  I have no pro=
blem=20
> with for_each as long as simple unary functions are used.  Introducing=20
> operator overloading to squeeze more functionality into the limits of the=
=20
> unary function results in complicated code.  Maybe the complicated code i=
s=20
> more versatile, but that means there are more test cases to perform. =20
> Operator overloading with for_each also yields terse code, which is=20
> esthetically pleasing.   The esthetics are lost on myself after I've gaze=
d at=20
> the well-crafted code for an hour and I am still not sure of what it does=
.
>=20
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'm going to keep studying this operator overloading subject.  I havn't =
used=20
> it much.
>=20
Perhaps it would help instead of calling it "operator overloading"
to call it a function adapter.  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


--=20
Tanner Lovelace | lovelace@wayfarer.org | http://wtl.wayfarer.org/
--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--
GPG Fingerprint =3D A66C 8660 924F 5F8C 71DA  BDD0 CE09 4F8E DE76 39D4
GPG Key can be found at http://wtl.wayfarer.org/lovelace.gpg.asc
--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--
 Those who are willing to sacrifice essential liberties for a little=20
 order, will lose both and deserve neither.  --  Benjamin Franklin=20

 History teaches that grave threats to liberty often come in times
 of urgency, when constitutional rights seem too extravagant to=20
 endure.  --  Justice Thurgood Marshall, 1989=20

--=-NNbX4oZ3cXNlugFLVnyZ
Content-Type: application/pgp-signature; name=signature.asc
Content-Description: This is a digitally signed message part

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

iD8DBQA8aCsHzglPjt52OdQRAnt7AKDeGOgHhTLRH/Btrd+ueJvxfNKWowCgtWSB
FpZPHXntMypJKo9Zpxwro34=
=luEi
-----END PGP SIGNATURE-----

--=-NNbX4oZ3cXNlugFLVnyZ--