Boost logo

Boost :

From: William Kempf (sirwillard_at_[hidden])
Date: 2000-11-17 16:41:45


--- In boost_at_[hidden], Douglas Gregor <gregod_at_r...> wrote:
> On Fri, 17 Nov 2000 20:54:33 -0000
> "William Kempf" <sirwillard_at_m...> wrote:
>
> > --- In boost_at_[hidden], Douglas Gregor <gregod_at_r...> wrote:
> > > On Fri, 17 Nov 2000 19:40:05 -0000
> > > 1) I use one "Callback" class that takes any number of
parameters
> > > instead of having many Callback0, Callback1, ..., CallbackN
> > > classes.
> >
> > In theory I really like this. Unfortunately, it requires partial
> > template specialization and so may hinder or prevent
implementation
> > on VC++, which I think is a major problem. It's definately an
idea
> > worth looking into, however.
>
> I believe that we need partial specialization in any case. Even if
we use Callback0, Callback1, etc. classes, we still (might) need a
void (partial) specialization. e.g.,
>
> template<typename Arg1, typename Arg2>
> struct Callback2<void, Arg1, Arg2> { ... };
>
> I haven't toyed with the idea (since I tend to ignore VC++ as much
as I'm allowed), but we may be able to come up with an implementation
which correctly omits the "return" when the return type is void
without using partial specialization.

This particular issue has a VC++ work around known to work, even if
the resulting code is hard to read ;). The multiple arguments are
MUCH harder to work around.

> > > 3) I have explicit classes (each derived from EventBase) which
> > > allow callbacks to member functions, free functions or
> > > functors. It appears that the William Kempf and Jesse Jones'
> > > solution would use only functors (relying on another library
> > > (the lambda library?) to build functors out of free/member
> > > functions). This makes it tougher to include the bool
> > > conversion (how do we know if a functor has a real target or
> > > not?), which I consider essential.
> >
> > The bool conversion can be handled by inclusion of a default
> > constructor that sets the "impl" pointer to null. The actual
functor
> > is an internal detail that does not effect this in any way. I
find
> > it useful to leave things as they are in our implementation in
order
> > to not duplicate the effort of creating functors yet again.
There
> > are already numerous libraries available for doing this,
including
> > the standard library that comes with every compiler. Libraries
such
> > as Lambda do a much better job of this than we could possibly do
with
> > out duplicating a tremendous amount of effort, and with no clear
> > benefit.
>
> The reason I originally decided to use separate classes
(FunctionEvent, MemberFunctionEvent) instead of only using a functor
is that I wanted to account for cases where the function/object
pointed to are null. In truth, this is probably not sufficient reason
to duplicate Lambda's functionality. Additionally, I wanted to leave
the door open for other types of events (derived from EventBase)
which may have different criteria for the bool conversion. Here's a
strange example that I don't believe can be covered with your version:
>
> class KeyboardInputEvent : public EventBase<char>
> {
> virtual operator bool() { return is_key_pressed(); }
> virtual char operator()() { return get_key_pressed(); }
>
> // implement other virtual methods as needed
> };
>
> Event<char> getUserInput = KeyboardInputEvent(...);
>
> if (getUserInput) {
> char input = getUserInput();
> // Act on the user's input...
> }
>
> I do believe this example has merit, and that existance of a
functor is not the only criteria by which the bool conversion should
be performed. Perhaps I can conjure a more convincing example.

Please do. This particular example at first seems compelling.
However, you're looking at this as an "event" while I'm looking at it
as a "callback". Though related they are different concepts.
Realizing that, if the above functionality is not common it may make
more sense to have both concept types, building the event type out of
the callback type.
 
> > > 4) I provide an "event" helper function which builds an
> > > appropriate event object given the operands. Granted, this is
> > > not very useful if #3 isn't considered useful.
> >
> > Right. The constructor for the callback is enough here so long
as
> > we're in agreement about #3. Hopefully I made enough of a case
in my
> > response to #3 to at least spark detailed debate if not enough to
win
> > you over completely.
>
> Not yet :). Also, I don't believe the callback constructor is
enough because it requires too much (unnecessary) typing. For
instance, define an event as such: Event<float, int, int> myEvent;
>
> Now, if we want to create a new event/callback to stick in myEvent,
we do it this way:
> myEvent = Event<float, int, int>(put_a_functor_here);

Well, to me it seems that typically a callback will have a typedefed
signature, much as we usually do with function pointers in C. So
this isn't a huge issue. However, even with out the typedef it may
be possible to implement a make_callback() template function to
simplify creation of the callback, same as done with your event(). I
wasn't really advocating the removal of the creation function, only
questioning the need for multiple class types for functions, member
functions and functors.
 
> The usefulness of the "event" function is that, from a free
function pointer or a member function pointer passed to event, we
already know the argument types, so we can construct the appropriate
(Member)FunctionEvent object.
>
> The assignment operation could, of course, be templated for any
functor, so we just write:
> myEvent = put_a_functor_here;
>
> In this case I worry about type safety, though there a probably a
type-safe solution to this that I'm not seeing.

Might be simplest to just include a reassign() method instead of an
operator=(). This would be as type safe as the templated constructor
in the original implemenation.

Bill Kempf


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