Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why Qt signals' arguments can't be defined with typedef types?

For a Qt5/c++11 project, I'm using a QMediaPlayer object (named audio_player) with its positionChanged() signal:

This piece of code is ok:

connect(this->audio_player,
        SIGNAL(positionChanged(qint64)),
        this,
        SLOT(audio_position_changed(qint64)));

But this one doesn't work:

typedef PosInAudio qint64;

connect(this->audio_player,
        SIGNAL(positionChanged(PosInAudio)),
        this,
        SLOT(audio_position_changed(PosInAudio)));

At run-time I get the message "QObject::connect: No such signal QMediaPlayer::positionChanged(PosInAudio)"

I was baffled to see that even a type defined with #define wasn't ok:

#define PosInAudio qint64

connect(this->audio_player,
        SIGNAL(positionChanged(PosInAudio)),
        this,
        SLOT(audio_position_changed(PosInAudio)));

(same error message as above)

Is this the expected behavior ? Or do I make a mistake?


As explained above (thank you Matteo Italia), everything's ok if you use the Qt5 new signal-slot syntax described here.

like image 931
suizokukan Avatar asked Aug 20 '14 10:08

suizokukan


1 Answers

The problem arises from the fact that the old-style connect actually works comparing strings to match the signal and the slot, and here the signature used in the signal declaration (void positionChanged(qint64)) and the one used in your connect call (void positionChanged(PosInAudio)) don't match if you are just comparing strings.

The SIGNAL and SLOT are essentially stringifying macros (the actual signature of the old-style connect involves const char * or equivalent stuff); connect performs a normalization on the received strings (removing unnecessary spaces, const references & co. - see QMetaObject::normalizedSignature - but again, with no knowledge of typedefs or namespaces) and tries to match them to the signals/slots lists found in the metaobject.

This list, in turn, is generated by the MOC, which has quite a vague understanding of C++ syntax and semantics, and extracts the signal and slots signatures quite brutally; so, neither the strings produced by MOC nor what is put into the SIGNAL and SLOT macros are aware of subtleties like typedefs or "equivalent" names (e.g. a type local to the current namespace, which, when referenced outside, needs to have its name prepended by a namespace), so the connect will fail if you have "complicated" (and non-literally matching) type names in your signal and slots.

The new-style (Qt5+) connect (mentioned in the comments by @peppe) should solve these issues (and permit neat stuff like connecting a signal to a lambda), but if you have to live with old-style connects to avoid problems you should always refer to types in the same way - e.g., if you use a typedef in your signal declaration, you have to use it in slots too; if you have namespaced types in the signal, prefix them with the adequate namespaces and do the same in the slots.

like image 159
Matteo Italia Avatar answered Nov 15 '22 07:11

Matteo Italia