Article View: comp.std.c++
Article #3425Re: Generic Object Callbacks
From: Roger S. Morris
Date: Fri, 23 Feb 1996 17:45
Date: Fri, 23 Feb 1996 17:45
129 lines
7243 bytes
7243 bytes
Hi, We've had to address the same problem.
We've developed a general-purpose callback class that can be used to
contain almost any kind of callback. This code is "under development"
in that I'm not convinced that it has the cleanest-possible interface.
The code works with the latest gnu compiler.
Why do I mention this in comp.std.c++? Well, firstly in order to respond
to the original poster. Secondly, I'd like to mention that this sort
of code would be much cleaner if the language had a notion of a
``parameter-list'' type, which would allow me to manipulate, store, and
pass along any list of parameters. Also, it would be nice if a function
of return type ``void'' would be allowed to return a void. For example,
void foo() {}
void bar() { return foo(); }
If anyone is interested in our code, I will place the code at the following
http address today: http://www.dtseng.com/sig/callback .
Any comments would be really appreciated.
--Roger Morris
Here are some of the comments from callback.H...
/// INTRODUCTION ////////////////////////////////////////////////////////////
//
// This file defines a general-purpose "CALLBACK HANDLE", an object that
// represents everything a caller needs for making a function callback.
// Here is an example:
// Suppose that class ``PushButton'' is some sort of graphical widget
// that performs a callback when "pushed". It's ctor might look like:
// PushButton::PushButton( string name, Win window, callback0 cb );
// where ``cb'' represents the function to be called.
//
// In order to have a function ``foo1'',
// void foo1();
// called by a PushButton ``pb1'', create ``pb1'' as follows:
// PushButton pb1(name,win, callback0(&foo1) );
// or simply:
// PushButton pb1(name,win, &foo1 );
//
// In order to have a member function ``foo2'',
// struct S { void foo2(); } s2;
// called by a PushButton ``pb2'', create ``pb2'' as follows:
// PushButton pb2(name,win, callback0_mf<S>(&s2,&s2::foo2) );
//
// In order to have a function ``foo3'',
// void foo3( const bool& );
// called with ``true'' when ``pbT'' is pushed and with ``false''
// when ``pbF'' is pushed, create ``pbT'' and ``pbF'' as follows:
// PushButton pbT(name,win, callback0_tag<bool>(&foo3,true) );
// PushButton pbF(name,win, callback0_tag<bool>(&foo3,false) );
//
// Lastly, suppose that ``PushButton'' actually passes a reference
// to an ``EventStruct'' to the callback. In this case, its ctor
// might instead look like:
// PushButton::PushButton( string, Win, callback1<EventStruct> cb );
// Though the ctor interface has changed, the code above that initializes
// ``pb1'', ``pb2'', ``pbT'', and ``pbF'' WILL STILL WORK PERFECTLY FINE
// as coded (because a callback1<EventStruct> can be constructed from a
// callback0). It is now possible, however, to have a function ``foo4'',
// void foo4( EventStruct& );
// called by a PushButton ``pb4'' by creating ``pb4'' as follows:
// PushButton pb4(name,win, callback1<EventStruct>(&foo4) );
// or simply:
// PushButton pb4(name,win, &foo4 );
// The purpose of the "callback handle" is to separate the "caller" from
// the "callee" as much as possible; neither should have to be concerned
// about the irrelavent (from its point of view) details of the other.
//
/// OVERVIEW ////////////////////////////////////////////////////////////////
//
// Use of these callback handles allow a function callback to be made without
// the caller having to know:
// - Whether the called function is a static (global) function or a member
// function,
// - What object the called function is a member of, if any,
// - What special callee-provided parameters must be passed, such as
// the ``void* tag'' parameter so-often used with Motif call-back
// functions.
// and without the callee having to:
// - Set up a special static function to wrap each member function in.
// - Bypass type checking by casting a ``void* tag'' argument.
// - Point a ``tag'' argument to a special intermediate class just to
// associate another piece of data with the callback.
//
// Other less-important features provided:
// - The callback handles are implemented as counted-reference handles,
// and so can be passed around or placed in lists without lots of
// copy constructor overhead.
// - The handles are default constructable, copy constructable, and
// equality comparable. This allows easy use within STL containers.
// - The actual handle objects contain virtual member functions and a
// single data element (a pointer), so their size is likely to be
// only that of a couple of pointers.
// (Note, once the compiler supports templated member functions, it
// will be possible to reimplement this without virtual member
// functions.)
// - The callee has the ability to invalidate its handles, and so
// cause an error to be thrown if a callback is attempted.
//
// Through use of these handles, a callback can receive up to 3 arguments:
// - "P1" is caller-provided,
// -- --
// - "P2" is caller-provided,
// -- --
// - "TAG" is callee-provided (such as Motif's ``void* tag'' param).
// --- --
//
// The callback's RETURN VALUE IS ALWAYS IGNORED.
//
// A caller which has parameters to pass will use a ``callback1<P1TYPE>''
// or a ``callback2<P1TYPE,P2TYPE>'' handle. A caller without
// arguments will use a ``callback0'' handle.
//
// If additional parameters or return data is needed, they must be grouped
// into P1, P2, or TAG (perhaps with pair<..>). (Alternatively, the user can
// extend this framework to handle more params or a return value, but things
// are already complicated enough. Perhaps someday it will be possible in
// C++ to parameterize parameter lists, not just individual parameters.)
//
---
[ To submit articles: Try just posting with your newsreader. If that fails,
use mailto:std-c++@ncar.ucar.edu
FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html
Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Technical Details
Message-ID:
<Dn8MAL.Evw@mv.mv.com>Path:
arc1-ca.pugleaf.net!chronicle.mti.sgi.com!austernReferences:
<pgpmoose.199602221531.14635@isolde.mti.sgi.com>Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!chronicle.mti.sgi.com!austern From: rsm@gateway.Dtseng.Com (Roger S. Morris) Newsgroups: comp.std.c++ Subject: Re: Generic Object Callbacks Date: 23 Feb 1996 09:45:18 PST Organization: Discrete Time Systems Corporation Approved: austern@isolde.mti.sgi.com Message-ID: <Dn8MAL.Evw@mv.mv.com> References: <pgpmoose.199602221531.14635@isolde.mti.sgi.com> NNTP-Posting-Host: isolde.mti.sgi.com X-Original-Date: Fri, 23 Feb 1996 16:39:57 GMT Apparently-To: comp-std-c++@uunet.mv.com X-Auth: PGPMoose V1.1 PGP comp.std.c++ iQBVAwUBMS39Uky4NqrwXLNJAQFgVwH7BXtVNrdao2Du46qbMLFJ6oFFWjvVVjBg N6J1dyhKl/3wpt9OMGxYmxOYHkO7oDzvxLVZYs3MPQWQ8mQxeE8F5g== =QRFD Originator: austern@isolde.mti.sgi.com