对于Qt5 / c ++ 11项目,我使用了一个QMediaPlayer对象(名为audio_player)及其positionChanged()信号:
这段代码没问题:
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:没有这样的信号QMediaPlayer :: positionChanged(PosInAudio)”
我很困惑地看到即使用#define定义的类型也不行:
#define PosInAudio qint64
connect(this->audio_player,
SIGNAL(positionChanged(PosInAudio)),
this,
SLOT(audio_position_changed(PosInAudio)));
(与上面相同的错误信息)
这是预期的行为吗?或者我犯了错误?
如上所述(感谢Matteo Italia),如果您使用here所述的Qt5新信号槽语法,一切正常。
答案 0 :(得分:7)
问题产生于旧式connect
实际上比较字符串以匹配信号和插槽,这里是信号声明中使用的签名({{ 3}})和connect
调用中使用的那个(void positionChanged(PosInAudio)
)如果只是比较字符串则不匹配。
SIGNAL
和SLOT
实际上是字符串化宏(旧式connect
的实际签名涉及const char *
或同等的东西); connect
对收到的字符串执行规范化(删除不必要的空格,const
引用& co。 - 请参阅void positionChanged(qint64)
- 但同样,不知道typedef
s或命名空间并尝试将它们与元对象中的信号/插槽列表进行匹配。
反过来,这个列表是由MOC生成的,它对C ++语法和语义有相当模糊的理解,并且非常粗暴地提取信号和插槽签名;因此,MOC生成的字符串和放入SIGNAL
和SLOT
宏的字符串都不会识别typedef
或“等效”名称等细微差别(例如当前的本地类型)命名空间,当在外部引用时,需要在命名空间前加上其名称),因此如果信号和插槽中有“复杂”(和非字面匹配)类型名称,connect
将失败。 / p>
新式(Qt5 +)connect
(在 @peppe 的评论中提到)应解决这些问题(并允许将信号连接到lambda等整洁的东西),但如果您必须使用旧式connect
以避免出现问题,则应始终以相同方式引用类型 - 例如,如果您在信号声明中使用typedef
,则必须使用它也在插槽中;如果信号中有命名空间类型,则在前面加上适当的命名空间,并在插槽中执行相同操作。