Boost logo

Boost :

From: Dean Michael C. Berris (mikhailberis_at_[hidden])
Date: 2006-03-05 12:42:24


On Fri, 2006-03-03 at 01:30 -0600, Rene Rivera wrote:
> >
> > I have just uploaded a simple implementation to the vault of my proposed
> > listener-registry pattern implementation.
>
> Hm, doesn't seem to be much there, and hence it's hard to comment on it.
> A little bit of explanatory documentation would go a long way ;-)
>

Thanks. It never really crossed my mind to write some simple
documentation regarding it. I should come up with something in a short
while. :)

> > 1) It doesn't use MPL (yet) -- since because the pattern is quite
> > simple, I have implemented it such that the listener class should be
> > inherited, and a handle() method should be overridden by the specific
> > listeners. This would change, once I start learning more about MPL --
> > which should make the implementation more flexible at compile time.
>
> Change into what?
>

The current implementation requires that a method named handle() be
defined which takes in a const reference to a user-defined type. This is
severely limiting, and does not fit well with the STL style of
overriding operator() () to provide functor functionality.

For instance, I would like to be able to do something like this:

struct my_registry : public listener_registry<int, (double, double)> {
        ...
};

static my_registry global_dispatcher;

struct my_listener1 : public listener<int, (double, double)> {
        my_listener1() : listener(global_dispatcher, 1);
        ...
        int operator() (double a, double b) {
                return do_some_processing(a, b);
        }
        ...
};

struct my_listener2 : public listener<int, (double, double)> {
        my_listener2() : listener(global_dispatcher, 1);
        ...
        int operator() (double a, double b) {
                return do_some_other_processing(a, b);
        }
        ...
};

And maybe perhaps simplify it by creating the listeners during compile
time, and just bind them to methods. I don't know if that's possible: to
make named types during compile time using template metaprogramming
techniques, but as I learn more and more about Boost.MPL everyday, I
sure hope it will let me do that.

My goal really is to be able to do the following:

struct my_functor {
        int operator() (double a, double b) {
                return 1;
        }
};

struct my_listener1 : public listener<int (double, double),
        /* to bind to signal */ 1,
        /* functor type name */ my_functor> {
        my_listener1 : listener(global_dispatcher, my_functor()) { };
        ...
};

Or maybe even:

struct my_functor {
        ...
};

GENERATE_LISTENER(my_listener1, (int (double, double)), 1, my_functor);
GENERATE_LISTENER(my_listener2, (int (double, double)), 2, \
        my_other_functor);

Using some major preprocessor magic.

> > 2) It maps inputs to processors, while Boost.Signals allows you to use a
> > signal which maps to different slots (which are all called in turn, once
> > the signal is invoked). The listener-registry pattern implementation
> > defines a registry to which listeners register themselves -- the
> > registry then does the routing of inputs to the listeners. Think event
> > driven processing, where a listener listens for a specific event and is
> > invoked only when the specific input is passed into the registry which
> > it is registered to.
>
> Over the past few weeks I've been implementing something basically like
> that for a model-view-* system. And as I understand your goals, does
> what you want. That is, it does signal to call dispatching from many
> sources to many endpoints through a single router/dispatcher. To give
> you some idea the signal points would look like:
>
> reflection->Signal(signal::Resize((width = 20, height = 30)));
>
> The registration of endpoints like:
>
> void handle_resize(Window * window, int w, int h);
>
> *reflection << MakeReflector<Resize>((
> signal = boost::bind(&handle_resize, my_window, _1, _2) ));
>
> Types are enforced at compile time, all around, even though the
> implementation uses boost::any for it's safe type erasure. There's some
> other type definitions involved to make the above possible of course ;-)
>

Basically that's essentially what I've been trying to do, and have been
having a hard time making generic. I have been encountering a lot of
problem domains where the handling of inputs change from time to time,
and routing rules are better implemented in a single component than many
different cascading components/class hierarchies.

> > The file is up at the vault (listener.tar.gz) and unfortunately, I chose
> > to use the CppUnit test framework, and the GNU Make build system -- I've
> > tried it on Ubuntu Linux 5.10, and requires libcppunit to build the test
> > case.
>
> Kinda limits how many people will give you feedback :-\
>

Yeah. I also need to learn the Boost testing framework, and learn Bjam
for the build process.

Too much stuff to learn in so little time... :)

-- 
Dean Michael C. Berris
Mobile +639287291459
URL http://mikhailberis.blogspot.com
YMID: mikhailberis

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk