为什么 Qt 信号的参数不能用 typedef 类型定义? [英] why Qt signals' arguments can't be defined with typedef types?
问题描述
对于 Qt5/c++11 项目,我使用 QMediaPlayer 对象(名为 audio_player)及其 positionChanged() 信号:
For a Qt5/c++11 project, I'm using a QMediaPlayer object (named audio_player) with its positionChanged() signal:
这段代码没问题:
connect(this->audio_player,
SIGNAL(positionChanged(qint64)),
this,
SLOT(audio_position_changed(qint64)));
但是这个不起作用:
typedef PosInAudio qint64;
connect(this->audio_player,
SIGNAL(positionChanged(PosInAudio)),
this,
SLOT(audio_position_changed(PosInAudio)));
在运行时我收到消息QObject::connect: No such signal QMediaPlayer::positionChanged(PosInAudio)"
At run-time I get the message "QObject::connect: No such signal QMediaPlayer::positionChanged(PosInAudio)"
我很困惑,即使是用 #define 定义的类型也不行:
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?
如上所述(感谢 Matteo Italia),如果您使用 Qt5 新的信号槽语法描述 这里.
As explained above (thank you Matteo Italia), everything's ok if you use the Qt5 new signal-slot syntax described here.
推荐答案
问题源于旧式 connect
实际上可以比较 strings 以匹配信号和插槽,这里是信号声明中使用的签名(void positionChanged(qint64)
) 和 connect
调用中使用的那个 (void positionChanged(PosInAudio)
) 不匹配,如果你是只是比较字符串.
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.
SIGNAL
和 SLOT
本质上是字符串化宏(旧式 connect
的实际签名涉及 const char *
或等效的东西);connect
对接收到的字符串执行规范化(删除不必要的空格,const
引用 & co. - 参见 QMetaObject::normalizedSignature
- 但同样,不知道 typedef
s 或命名空间)并尝试将它们与元对象中的信号/槽列表进行匹配.
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 typedef
s or namespaces) and tries to match them to the signals/slots lists found in the metaobject.
反过来,这个列表是由 MOC 生成的,它对 C++ 语法和语义的理解相当模糊,并且相当残酷地提取信号和插槽签名;因此,无论是 MOC 生成的字符串还是放入 SIGNAL
和 SLOT
宏中的字符串,都不知道诸如 typedef
或等效"之类的细微之处名称(例如,当前命名空间的本地类型,当在外部引用时,需要在命名空间前面加上其名称),因此如果复杂"(和非字面上匹配)类型名称在您的信号和插槽中.
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 typedef
s 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.
新式 (Qt5+) connect
(在 @peppe 的评论中提到)应该解决这些问题(并允许像将信号连接到 lambda),但是如果您必须使用旧式 connect
以避免出现问题,您应该始终以相同的方式引用类型 - 例如,如果您在你的信号声明,你也必须在插槽中使用它;如果信号中有命名空间类型,请在它们前面加上足够的命名空间,并在插槽中执行相同操作.
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 connect
s 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.
这篇关于为什么 Qt 信号的参数不能用 typedef 类型定义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!