🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.std.c++
Article #3425

Re: Generic Object Callbacks

#3425
From: Roger S. Morris
Date: Fri, 23 Feb 1996 17:45
129 lines
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!austern
References: <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