|
Boost : |
From: Karl Nelson (kenelson_at_[hidden])
Date: 2000-11-22 13:06:32
> --- In boost_at_[hidden], Kevlin Henney <kevlin_at_c...> wrote:
> > In message <v03110700b641067df0b8@[153.32.222.4]>, Jesse Jones
> > <jejones_at_a...> writes
> > >I've uploaded a new version of my callback classes (see the
> Callbacks2
> > >directory in the vault). Like Doug Gregor's this version has the
> nice
> > >property of not requiring clients to encode the number of
> arguments in the
> > >callback class name.
> >
> > I might be missing something, but why is this a nice property? It
> seems
> > to open up the possibility of runtime errors and require that all
> result
> > types are default constructible. I don't think either of this, esp
> the
> > first point, is really that desirable.
>
> I've not looked at Jesse's new code yet, but Doug's code doesn't seem
> to open up the possiblity of runtime errors that you suggest.
> Neither does it require that any parameters or other types be default
> constructible. Care to elaborate on the problems you think you see?
>
> As for why it's desirable... it eliminates redundant information from
> the declaration. Why should you have to specify the number of
> parameters when you declare the type with explicit parameters? It's
> just cleaner to say:
>
> callback<void, int, float> cb;
>
> instead of:
>
> callback2<void, int, float> cb;
I really don't agree with this.
1) All of the classes written to
hide the extra arguments inevitably show up when an error occures
thus spitting something like this to the user...
an error has occured in class callback<void,int,float,unused,unused,unused>
Thus it really isn't transparent to the user.
(See the horrible errors spit by basic_string as to how annoying this
can be.)
2) Second it makes for really poor code clarity as the class will
have to implement all of the operator() even through it uses
only one of them...
class callback {
...
return_type operator()() { ... }
return_type operator()(P1 p1) { ... }
return_type operator()(P1 p1,P2 p2) { ... }
return_type operator()(P1 p1,P2 p2,P3 p3) { ... }
return_type operator()(P1 p1,P2 p2,P3 p3,P3 p3) { ... }
...
};
3) It only saves one charactor. :-) The same things could be achieved
with a base class with all the common stuff and then derive it to
add the arguments.
class callback { // not a template
bool empty();
void clear();
... // common stuff
};
template <class R, class P1 >
class callback1 {
... // specific stuff
R operator()(P1 p1);
};
Which insidentally extracts with VC++ and other code browsers
to make more sense.
4) It bars adding additional optional arguments which may be
useful. Ie, since the callback may be unconnected how do we specify
what to return in case of there is nothing connected.
imagine this
template <class R, class P1, class P2, class RT=trait<R> >
class callback2
{
R operator()(P1 p1,P2 p2)
{ if (empty) return R(RT::default_value); ... }
};
(This also saves the default constructor argument.
SigC uses this for a number of classes. (Though I
avoid it for slots as then copy gets fun.)
Without the number you have to write something like...
callback<void,int,unused,unused,unused,my_return_trait>
^^^^^^^
(how many should I type? depends on the version of the library!)
5) It caps the number of callback which limits the application
somewaht. That is with the callback#, the user can always call
the macro generator to produce another set of classes for a
larger number of parameters.
6) It encourages gobs of template land meta programming which can slow
some compilers to a grinding halt and is some of the least portable code
back to the weaker compilers. ( Read we will get something which
VC++ likes but is kludgy as all hell.) Then again implementing
many levels of class can do the same.
For all of these reasons SigC went with numbered classes.
I hope you consider carefully these reasons before chosing to do
differently.
--Karl
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk