[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
RE: [paragui-dev] replacing callbacks with boost::function
From: |
Dinand Vanvelzen |
Subject: |
RE: [paragui-dev] replacing callbacks with boost::function |
Date: |
Thu, 29 Aug 2002 12:34:14 +0200 |
I myself found boost to be rather chaotic. Plus most importantly it
means including another large lib. In my project I could use borlands
VCL for example but that would have increased my file size dramaticly ..
same goes for boost as far as I know.
Greetz.
DV
-----Original Message-----
From: address@hidden
[mailto:address@hidden On Behalf Of Ulrich
Eckhardt
Sent: Wednesday, August 28, 2002 17:29
To: address@hidden
Subject: [paragui-dev] replacing callbacks with boost::function
(note: please keep me in the CCs!)
Hi Folks!
I have been hacking paragui-1.0.2 a bit (mostly in order to teach myself
boost's function) and found that replacing callbacks was pretty easy. I
got
paragui and the tests to compile and run using GCC 3.2 and boost 1.28. A
tarball with the changed sources is available at
http://home.knuut.de/Doomster/paragui-1.0.2boost.tar.bz2, all changes
are
#ifdef PARAGUI_USE_BOOST_CALLBACKS (which is currently defined in
paraconfig.h but could as well be moved into a configure-option).
I know that the modified version is stable and that such changes will
never
be made to a stable version. If there is interest, I would take a shot
at the
current cvs.
btw: is there an IRC-channel where you meet ? I usually hang around on
freenode (former openprojects.net), nickname doomster.
cheers
Uli
What's the difference ?
-----------------------
Boost.Function (http://boost.org/libs/function/doc/tutorial.html) is a
generic wrapper around function-like objects. It comes with a set of
helpers
that make things like the void* that is passed with current callbacks
unnecessary. If you need the pointer, you can simply bind one arg of
your
function to the value you want.
What's the difference to SigC++ ?
---------------------------------
SigC++ is more intrusive but on the other side possibly more secure.
SigC++
requires you to derive every object you want to connect to (if it is not
a
static/global object or plain function) from SigC::Object.
It automatically removes all existing callbacks that still point to the
object in the dtor, which makes it a bit more save. Furthermore, you can
connect several recipients(slots) to one sender(signal), making it a bit
more
flexible (although I don't see any immediate advantage in that feature
for
paragui).
What has changed ?
------------------
The typedef for MSG_CALLBACK has changed:
typedef bool (*MSG_CALLBACK)
(int id, PG_Widget* widget, unsigned long data, void *clientdata);
typedef bool (PG_EventObject::*MSG_CALLBACK_OBJ)
(int id, PG_Widget* widget, unsigned long data, void* clientdata);
have both been replaced by
typedef boost::function<bool, int, PG_Widget*, unsigned long>
MSG_CALLBACK;
(read this like 'function returning a bool and taking an int, a
PG_Widget*
and an unsigned long'). As you see the 'void* clientdata' was removed,
I'll
explaing later how to get the same effect.
Accordingly, PG_MessageObject's two methods to register a callback,
SetEventCallback and SetEventObject have been merged. Other widgets
(popupmenu) had to be modified in the same way.
Also note that event-recipients need not be derived from a common
baseclass
for this to work.
How do I get my userdata passed with the callback ?
---------------------------------------------------
assuming the callback is a member function:
bool MyClass::callback
(int id, PG_Widget* widget, unsigned long data, void* clientdata)
when assigning this to a boost::function, this becomes a
boost::function<bool,MyClass*,int,PG_Widget*,unsigned long,void*>
In order to fit this into a generic callback, we have to remove the
'MyClass*' and the 'void*' parameter:
boost::bind(&MyClass::callback, myclass_ptr, _1, _2, _3, userdata)
The first parameter to bind() is the original function, followed by the
parameters. The funny '_1' etc are placeholders (template-voodoo) to
mark the
position where the args of the resulting functor are passed to the
original
function. Note here that there is no more reason that userdata has to be
void*, you can use the whole C++ typechecking!
Example:
#ifdef PARAGUI_USE_BOOST_CALLBACKS
MSG_CALLBACK cb =
boost::bind(&PG_DropDown::select_handler, this, _1, _2, _3,
(void*)0);
my_DropList->SetEventCallback(MSG_SELECTITEM, cb);
#else
my_DropList->SetEventObject(MSG_SELECTITEM, this,
(MSG_CALLBACK_OBJ)&PG_DropDown::select_handler);
#endif
Of course, this could be written in a single line. Also note that the
(void*)
is necessary lest the compiler assume the zero was an integer. OTOH it
could
be removed if select_handler wouldn't take a 'void*' it doesn't really
use...
What are the drawbacks ?
------------------------
Very little imho. One thing of course is the dependancy on another
library,
another is that the compiler-errors that improper use of Boost.Function
creates are very hard to parse (due to heavy template usage).
The biggest lack currently is that PG_UnregisterEventTarget cannot be
implemented in that scheme, it simply doesn't fit into the design. Some
tests-apps call this function for cleanup. This of course bites programs
that
dynamically modify their GUI. Those programs would have to be modified
so
that instead of unregistering an object they unregister every callback
connected to that object, which implies they have to keep track of
connections themselves.
_______________________________________________
paragui-dev mailing list
address@hidden
http://mail.freesoftware.fsf.org/mailman/listinfo/paragui-dev