Boost logo

Boost :

From: William Kempf (sirwillard_at_[hidden])
Date: 2000-11-18 11:25:41


--- In boost_at_[hidden], Douglas Gregor <gregod_at_r...> wrote:
> On Fri, 17 Nov 2000 23:59:10 -0000
> "William Kempf" <sirwillard_at_m...> wrote:
> Taking a selective on/off mechanism and adapting it to always be on
> (as is needed for a callback) is easy to do, I'm just worried that
if
> we implement the least common denominator we will make it much
tougher
> to add that selective on/off mechanism (would it require an
additional
> functor? new member functions in the functor?).

template <typename R, ...>
class basic_event
{
public:
   basic_event(callback cb) : m_cb(cb) { }
   R operator()(...) { return ...; }
   virtual bool empty() { return m_cb.empty(); }
   ...
};

Building what you want from the basics is trivial, and IMHO the
correct way to go. Why add complexity and baggage to a simple
concept when the more complex concepts can be built from the basics?
    
> > > 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.
> >
> > This kind of safety should really be addressed by the code that
> > implements the functors.
>
> What should a functor do, then, if it gets a NULL pointer? The
options
> I currently see are:
> 1) Immediatly throw an exception.
> 2) Throw an exception when the function call operation is
> invoked.
> 3) Don't dereference, but don't complain.

I see what you're getting at. This seems like it's best left
to "undefined behavior" with the likely result being a segfault when
first dereferenced. As long as the callback type allows for "null"
behavior it seems highly unlikely that a NULL function pointer will
be used to construct it.

If that's not good enough, then functors should really handle the
problem, and do so the same way that you're advocating for
event/callback (i.e. they'd have a bool conversion). We can't
enforce this since even the standard functors don't behave this way,
but that's precisely why I don't see it as a real problem.

> > > > > 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.
> >
> > Not when applied to Lambda expressions. Does the following
really
> > make sense?
> >
> > callback<void, int> cb;
> > cb = cout << free1 << endl;
> >
> > In contrast, reassign is understandable and intuitive for either.
>
> Why not allow both and let the user decide what is readable? (even
> cb.reassign(cout << free1 << endl); would confuse me, though I can't
> say I've familiar with the lambda library).

If both are type safe (I'm not sure what problems you were alluding
to before) then this seems at least somewhat reasonable.
 
> > > 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.
> >
> > This can be handled with Concept Checking :). No, I don't have
code
> > to do this yet, but I don't see any other way to handle arbitrary
> > functors.
>
> In this case we would probably need a functor_traits class to dig
out
> the number and types of arguments. I used a simple FunctorTraits
class
> (which contains a "nArgs" value given the number of arguments, a
Result
> typedef, and Arg1, Arg2, ..., ArgN typedefs giving the argument
types).
> A GetArg<Functor, ArgNum> class gets the appropriate argument type
> (either a type, or "Unused" if ArgNum > nArgs).

I'm not sure we need a traits class. The pertinent info (number and
types of arguments) can be gleaned from the callback itself. With
out partial specialization we'll have to perform some hackery for
VC++, but I don't think it impossible to insure functor compatibility
at construction time. I'll try to come up with a prototype in the
next few days.

Bill Kempf


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