The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

stl boffins - can I do this?

I want to use for_each in what seems to be a slightly unusual way. What I want to do is have each iteration pass the instance retrieved form the collection as an argument to a method instance in a particular object. Basically, a for_each equivalent of something like:

MyCollection col;
Thing* p;
...
for (MyCollection::iterator it = col.begin(); it != col.end(); ++it)
{
 p->someMethod(*it);
}

Can I do it? Is there some other nice to read way of doing the same thing?

Wednesday, November 15, 2006
 
 
#include <vector>
#include <algorithm>
using namespace std;

int main(int argc, char* argv[])
{
    class Bar {};
    typedef vector<Bar> MyCollection;
    MyCollection col;
    class Thing
    {
    public:
        void someMethod(Bar& b) {}
    };
    Thing* p;
    for (MyCollection::iterator it = col.begin(); it != col.end(); ++it)
    {
        p->someMethod(*it);
    }
    struct Foo
    {
      Thing* m_p;
      Foo(Thing* p) : m_p(p) {}
      void operator() (Bar& x) { m_p->someMethod(x); }
    };
    Foo foo(p);
    for_each(col.begin(),col.end(),foo);
    return 0;
}
Christopher Wells Send private email
Wednesday, November 15, 2006
 
 
Hrmmph. That's very similar to what I already had!

The differences being that yours has a collection of Bars while mine has a collection of Bar*s, and yours compiles while mine...
Agh! I hate templates!
Wednesday, November 15, 2006
 
 
"I want to use for_each in what seems to be a slightly unusual way. "

Actually, this is far from unusual; it is in fact the "Visitor pattern" -- The class Thing visits each of the collections members in turn and does something to them.
Katie Lucas
Thursday, November 16, 2006
 
 
Off the top of my head, something like this might do:

for_each(col.begin(),col.end(),bind1st(mem_fun(&Thing::someMethod),p)))

Note: when I was into it, I always had great difficulty getting this sort of thing to compile :) -- however I think the principle is sound.

mem_fun gives you (in this case) a 2ary functor, whose first arg is the this pointer and whose second is the argument to the 1ary member function that you supplied.

bind1st takes a 2ary functor, and gives you a 1ary one, that calls the orginal functor with the bound argument as the 1st argument and the passed argument as the 2nd.

So the upshot is that in this case for_each will be supplying the argument to the member function (the item in the collection), and bind1st takes care of supplying the this pointer to the member function (p).

Apart from the making-it-compile bit, and the syntax, it is actually pretty simple. Certainly more so than my description probably implies :-\
Tom_
Thursday, November 16, 2006
 
 
Oops, I think an extra ) snuck in there! Sorry about that.

(Like I said, I always had difficulty making it compile :)
Tom_
Thursday, November 16, 2006
 
 
Tom_: You sure that works with a function that accepts a reference? To make it compile I had to pass Bar by value.

/usr/include/c++/4.0.0/bits/stl_function.h:405: error: forming reference to reference type 'Bar&'

(In Visual C++: ...error C2529: '_Right' : reference to reference is illegal...)
Nate Silva Send private email
Thursday, November 16, 2006
 
 
I'm new-ish to STL myself. This thread got me playing with some of the functional stuff in Boost. This seems to work nicely:


#include <boost/functional.hpp>

for_each(col.begin(), col.end(),
    boost::bind1st(boost::mem_fun(&Thing::someMethod), p));

And for why it works:
http://boost.org/libs/functional/binders.html#refref
Nate Silva Send private email
Thursday, November 16, 2006
 
 
> Actually, this is far from unusual; it is in fact the "Visitor pattern

What I meant was I'd never seen for_each used in this kind of way. Then again I don't like stl much so tend not to use it except where necessary.

> I always had great difficulty getting this sort of thing to compile

Heh. Yeah, me too, though it is now working. The compiler kept complaining it couldn't convert one of the arguments to basic_string. I don't know why it wanted to try and do that, but I had one of the args mixed up and it was fine once I'd sorted that.

Friday, November 17, 2006
 
 
Forgot to say: thanks for everyone's contributions.

Friday, November 17, 2006
 
 
See boost::bind (and pay attention to boost::ref).
The tutorial has some good examples...
See http://www.boost.org/libs/bind/bind.html#with_functions
David Cooper Send private email
Friday, November 17, 2006
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
 
Powered by FogBugz