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

时间:2014-08-20 10:42:56

标签: c++ qt types signals

对于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新信号槽语法,一切正常。

1 个答案:

答案 0 :(得分:7)

问题产生于旧式connect实际上比较字符串以匹配信号和插槽,这里是信号声明中使用的签名({{ 3}})和connect调用中使用的那个(void positionChanged(PosInAudio))如果只是比较字符串则不匹配。

SIGNALSLOT实际上是字符串化宏(旧式connect的实际签名涉及const char *或同等的东西); connect对收到的字符串执行规范化(删除不必要的空格,const引用& co。 - 请参阅void positionChanged(qint64) - 但同样,不知道typedef s或命名空间并尝试将它们与元对象中的信号/插槽列表进行匹配。

反过来,这个列表是由MOC生成的,它对C ++语法和语义有相当模糊的理解,并且非常粗暴地提取信号和插槽签名;因此,MOC生成的字符串和放入SIGNALSLOT宏的字符串都不会识别typedef或“等效”名称等细微差别(例如当前的本地类型)命名空间,当在外部引用时,需要在命名空间前加上其名称),因此如果信号和插槽中有“复杂”(和非字面匹配)类型名称,connect将失败。 / p>

新式(Qt5 +)connect(在 @peppe 的评论中提到)应解决这些问题(并允许将信号连接到lambda等整洁的东西),但如果您必须使用旧式connect以避免出现问题,则应始终以相同方式引用类型 - 例如,如果您在信号声明中使用typedef,则必须使用它也在插槽中;如果信号中有命名空间类型,则在前面加上适当的命名空间,并在插槽中执行相同操作。