I have a few general questions about passing user defined classes through the signal/slot mechanism, as I’m having trouble reconciling my understanding of the documentation with my actual experiences.
I have a pair of classes (let’s call them class MainFrame and class CutsDialog, since that’s pretty descriptive of what they do ). CutsDialog is a dialog window that is opened from MainFrame, through which the user (me ) can set a number of options and cuts for drawing events in MainFrame. These cuts are stored in a third class, class Selector. When changes are made and committed by CutsDialog, I would like to pass back the result to MainFrame (and, in future, potentially to other sinks, like a logger and a text console) through the Signal/Slot mechanism.
I can’t figure out how to do that, despite claims in various documentation that it should be possible. For instance, the User’s Guide says:
[quote]All signals and slots are normal class methods and can take any number of arguments of any type.
[/quote]
but the compiler complains vociferously if I try to Emit a signal matching an arbitrary signature:
followed by a long list of possible matches, none of which come close to being a match. In fact, the User’s Guide goes on to say that you can really only Emit for single parameters or “arrays of Long_t”. Further, the implementation in class TQObject seems to only support the basic Root types in a single argument Emit() (ie, Int_t, Bool_t, etc), along with pointers Long_t* and const char* (ie, not even really a Long_t, because it gets transported as a Long_t*, not as a contiguous block of memory of arbitrary length, so this doesn’t really answer my concerns below). I’ve tried a number of variations to get my object passed directly, and have failed. It really does not appear possible to do something like this:
or even
without some serious gymnastics to pack values into a Long_t (which you can’t do easily for objects that aren’t the same size as a Long_t … and which, in any case, is a far cry from passing “any number of arbitrary type”). Am I interpreting my experience correctly, or am I missing something? The documentation seems to be, at the very least, misleading in this case.
So, instead, I’m signaling with a pointer to the Selector owned by the CutsDialog (although, you really can’t do that, either … you must cast to const char *, and then cast back to the proper type in the slot) … and therein begins my second question. I’d certainly prefer signaling by value, not pointer, because the latter brings up all sorts of potential problems with respect to object lifetime and ownership. In particular, I find no guarantees in the documentation that the processing of Emit() is synchronous, although the current implementation appears to be … in fact, this Root Talk discussion from last September briefly mentioned the possibility of queued, asynchronous processing becoming likely or available in the future. Then, signaling by pointer would become quite dangerous, as the lifetime of the pointee may be over before the slot gets called. In my dialog, for instance, I Emit() the signal just before the dialog box closes itself and commits suicide … in this case, the Selector could be long gone well before it’s clients get told to look at it.
Practically, I guess, since there are a number of places where root signals by pointer (many Emit(“Event_t*”,e) instances, for example), this is probably not a large concern. Am I right in this interpretation? Or could I be getting myself into trouble in future Root versions by passing pointers to objects around?
In any case, an implementation that really allowed arbitrary arguments to Emit() would be quite welcome.
Thanks in advance for your help, and greatest apologies for my long-winded post.