Boost logo

Boost :

From: Douglas Gregor (gregod_at_[hidden])
Date: 2000-11-17 18:46:36


On Fri, 17 Nov 2000 21:41:45 -0000
"William Kempf" <sirwillard_at_[hidden]> wrote:

> > 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.

I don't have the capability to test on VC++, but if the primary Callback
template were to have N+1 operator() overloads (corresponding to having
0..N arguments), would VC++ still die? Only one of the operator() will
be instantiated, so possibly we can pull some casting tricks to make the
other operator() overloads appear valid to the compiler.

IMHO, this is mostly a stylistic issue, unless someone finds a compelling
technical reason to support or reject either approach.
 
> 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.

The obvious question of "which does Boost need?" comes to mind. It seems
that the only difference between an event and a callback that we have
listed is that an event can turn itself off, which is to some extent a
minor difference, since a callback is just an event that is always on.
Are there any other differences that should be discussed?

Here are a few cases where turning events on or off may be useful:
1) The case above, where the event may or may not provide input. This
   would allow input sources to simply be event handlers, allowing easy
   swapping of input sources.
 
2) Events can be masked via some global variable. For instance, during
   initialization of a system we may want all events blocked.
          
3) Preventing an event from being triggered when it cannot be handled.
   If we are feeding events to an event handler and it is backed up, it
   can request that more events not be sent. While this could also be
   done via the event's return value, the cost of generating the event
   may be high.

  
> > 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

I think the reason we all do this in C is because function-pointer
syntax is ugly, unreadable, and just plain ugly. Typedefs require the
user to look up two separate things (the typedef and the variable
declaration), and are not necessary with clean event/callback
declarations.

> 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 Functor implementation class is the only essential class. The
otherwise were included because I believed them to enhance type and
runtime safety (e.g., a NULL function pointer will never be called).
These concerns can be addressed in other places, but I think it would
be a mistake to allow a user to pass a NULL function pointer and then
have the callback code dereference it.

> > 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.

I think operator=() is most natural. As for the original templated
constructor, I dislike where an error will occur if an incorrect
functor type is given to the callback, which will be way down in the
detail::callback0_impl::operator() function. Using the more rigid
approach with the three implementation classes, this error will be
picked up when an assignment is attempted.

        Doug Gregor
        gregod_at_[hidden]


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