On 22/09/2011, at 3:20 AM, Thiago Macieira wrote:

> On Wednesday, 21 de September de 2011 18:49:04 Stephen Kelly wrote:
>>>> Another solution (also by way of adding an indirection) is to add a
>>>> function that emits, which is protected.
>>>> 
>>>> template <typename Klass, typename... Args>
>>>> void QObject::emitSignal(void (Klass:: *signal)(Args...), Args... args);
>>>> 
>>>> Then you'd write:
>>>> emitSignal(&Me::textChanged, newText);
>>>> instead of:
>>>> emit textChanged(newText);
>>>> 
>>>> The template magic to make that happen is already present.
>>>> 
>>>> However, it would be completely source-incompatible with the existing
>>>> code, which is a big no-no. It would require making the signal functions
>>>> themselves not do anything -- only serve as identifiers.
>>> 
>>> For source compatibility they could be implemented by moc to work as
>>> currently, no?
>> 
>> Oh, they need to keep the current implementation so that SIGNAL and SLOT
>> based connections still work. Never mind me.
> 
> The old connection mechanism is almost guaranteed to work.
> 
> The problem is to update "emit" lines, which are calls to functions that 
> cause 
> the signal to be emitted.
> 
> Also note that the solution above doesn't fix the following case:
> 
>       otherObject->emitSignal(&Them::textChanged, newText);
> 
> Just as it doesn't protect today:
>       emit otherObject->textChanged(newText);
> 
> The big difference is that "emitSignal" would be protected in QObject, so any 
> class deriving from QObject would have access to it.
> 
> We've been looking at this for a year. If anyone has more interesting ideas, 
> they are more than welcome. But please try to write the proof of concept 
> first.
> 
> Our conclusion is that if you want compile-time checking of the arguments, 
> you 
> need to give up the protectedness of the emission.

I'll mention one approach not because I think it is the right one to use here, 
but rather just to potentially fuel further discussion. For reasons I won't go 
into, we have our own observer-based code which has similarities to what Qt's 
signal-slot mechanism offers. Instead of relying on string-based signatures, it 
uses addresses of instances of a specific event class, which we call EventID. 
We also have an event base class which we call ObservableEvent. Our equivalent 
of defining a signal is to define a subclass of ObservableEvent. We provide the 
EventID singleton that corresponds to an ObservableEvent subclass using a 
static function. A short code extract to give you an idea of how this works 
would be:

class SomeSignalEvent : public ObservableEvent
{
    QString  someString_;
public:
    SomeSignalEvent(const QString& s) : someString_(s) {}

    static const EventID&  eventID()   { ... }    // Implementation hidden to 
keep it simple
};

class SendingClass : public CanNotifyEvents    // I won't explain this, but 
it's similar to inheriting from QObject
{
    // ...
};

class ReceivingClass
{
public:
    void  handleSomeSignalEvent(const SomeSignalEvent& e);
};

In our code, you would create an observer for an event on a specific object 
something like this:

addObserver(sender, SomeSignalEvent::eventID(), receiver & 
ReceivingClass::handleSomeSignalEvent);


Now, let's say that, as per this discussion thread, you wanted to limit who can 
emit/raise the SomeSignalEvent. Specifically, let's say you only wanted 
SendingClass to be able to do that. In that case, you could make the 
constructor for SomeSignalEvent private and add SendingClass as a friend. You 
leave the eventID() static function public. This means only SendingClass can 
create/emit the event, but anyone can connect to / listen for that signal/event.

Now, it may look like more work and yes, there are some things that the above 
approach makes a bit harder than the current signal-slot mechanism, but it does 
allow you to have full compile time checking and it does allow you to have 
non-public emit access while still allowing public connect/listen access. I've 
simplified things a bit in the examples above. In our code, we have macros and 
templates handle all the gory details and it is actually very simple to use. 
We've also very much appreciated that receivers don't have to derive from a 
common base class, so it's easy to add connections where we want the receiver 
to be a private class defined within a .cpp file, for instance.

I reiterate that I'm not advocating this as a replacement for the current 
signal-slot mechanism. It isn't source compatible with it, obviously, and it is 
a bit different in how the receiver is defined. I mention it only as an example 
of something that does meet the requirements of being able to control who can 
emit/raise a signal while still allowing anyone to connect to it, all with 
compile-time checking.

--
Dr Craig Scott
Computational Software Engineering Team Leader, CSIRO (CMIS)
Melbourne, Australia



_______________________________________________
Qt5-feedback mailing list
Qt5-feedback@qt.nokia.com
http://lists.qt.nokia.com/mailman/listinfo/qt5-feedback

Reply via email to