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

sui*_*kan 5 c++ qt types signals

对于Qt5/c ++ 11项目,我使用了一个QMediaPlayer对象(名为audio_player)及其positionChanged()信号:

这段代码还可以:

connect(this->audio_player,
        SIGNAL(positionChanged(qint64)),
        this,
        SLOT(audio_position_changed(qint64)));
Run Code Online (Sandbox Code Playgroud)

但是这个不起作用:

typedef PosInAudio qint64;

connect(this->audio_player,
        SIGNAL(positionChanged(PosInAudio)),
        this,
        SLOT(audio_position_changed(PosInAudio)));
Run Code Online (Sandbox Code Playgroud)

在运行时我得到消息"QObject :: connect:没有这样的信号QMediaPlayer :: positionChanged(PosInAudio)"

我很困惑地看到即使用#define定义的类型也不行:

#define PosInAudio qint64

connect(this->audio_player,
        SIGNAL(positionChanged(PosInAudio)),
        this,
        SLOT(audio_position_changed(PosInAudio)));
Run Code Online (Sandbox Code Playgroud)

(与上面相同的错误信息)

这是预期的行为吗?或者我犯了错误?


如上所述(感谢Matteo Italia),如果您使用此处描述的Qt5新信号槽语法,一切都可以.

Mat*_*lia 7

问题来自于旧式connect实际上比较字符串以匹配信号和插槽的事实,这里信号声明(void positionChanged(qint64))中使用的签名和你的connect调用中使用的签名(void positionChanged(PosInAudio))如果你是只是比较字符串.

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

反过来,这个列表是由MOC生成的,它对C++语法和语义有相当模糊的理解,并且非常粗暴地提取信号和插槽签名; 所以,无论是通过MOC也不是什么产生的串放入SIGNALSLOT宏都知道像微妙的typedefS或"等同"的名称(如一个类型的本地当前的命名空间,其中,引用外时,需要将其名称由前缀命名空间),所以connect如果你有"复杂"会失败(和非字面匹配),输入你的信号和插槽的名称.

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

  • 这不是MOC"意识到"的问题,而是使用字符串比较来确定类型相等性的旧式连接.那当然是使用typedef,但也是非完全限定的信号(信号可能被声明发出一个本地类型,例如枚举,没有限定它,并且当连接到获得限定类型的插槽时分辨率中断).**所有这些问题都在Qt 5中使用新的基于PMF的连接语法解决.** (3认同)