为什么Qt信号的参数不能用typedef类型定义?

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

本文关键字:typedef 类型 定义 不能 Qt 信号 参数 为什么      更新时间:2023-10-16

对于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),如果使用这里描述的Qt5新信号槽语法,一切都没问题。

问题源于这样一个事实,即旧式的connect实际上可以比较字符串以匹配信号和插槽,并且这里信号声明(void positionChanged(qint64))中使用的签名和connect调用(void positionChanged(PosInAudio))中使用的签名不匹配,如果您只是比较字符串。

SIGNALSLOT本质上是字符串化宏(旧式connect的实际签名涉及const char *或等效的东西);connect对接收到的字符串执行规范化(删除不必要的空格,const引用&co.(参见QMetaObject::normalizedSignature -但同样,不了解typedef s或名称空间)并尝试将它们与元对象中找到的信号/插槽列表相匹配。

这个列表,反过来,是由MOC生成的,它对c++语法和语义有相当模糊的理解,并且非常残酷地提取信号和插槽签名;因此,MOC产生的字符串和放入SIGNALSLOT宏中的内容都没有意识到typedef s或"等效"名称的微妙之处(例如,当前名称空间的本地类型,当在外部引用时,需要将其名称加上名称空间),因此如果您在信号和插槽中有"复杂"(非字面匹配)类型名称,connect将失败。

新风格的(Qt5+) connect(在@peppe的评论中提到)应该解决这些问题(并允许整洁的东西,如将信号连接到lambda),但如果你必须与旧风格的connect一起生活以避免问题,你应该总是以相同的方式引用类型-例如,如果你在信号声明中使用typedef,你也必须在插槽中使用它;如果在信号中有名称空间类型,请在它们前面加上适当的名称空间,并在插槽中这样做。