为什么我不能调用 QMetaObject::invokeMethod(&threadObj, &QThread::start, Qt::QueuedConnection)?

Why can't I call QMetaObject::invokeMethod(&threadObj, &QThread::start, Qt::QueuedConnection)?

我有一个控制台应用程序,在 main() 中有一个 QCoreApplication 运行 事件循环。 这里我有一个对象,它是 QThread 的派生对象,实现了 run() 来做一些测试。 我希望线程在启动我的应用程序时启动,所以我调用了

QMetaObject::invokeMethod(&threadObj, &QThread::start, Qt::QueuedConnection);
return qapp.exec();

main() 结束时。

这是我的问题:为什么这不能编译?

QThread::quit 做同样的事情很好,但 QThread::exit 不行。 我认为它与 startexit?`

的参数有关

编译器错误看起来像这样顺便说一句:

d:\dev\project\project\main.cpp(49): error C2665: 'QMetaObject::invokeMethod': none of the 4 overloads could convert all the argument types
1>x:\hmi_qt5\qt\msvc2017_x86\debug\include\qtcore\qobjectdefs.h(448): note: could be 'bool QMetaObject::invokeMethod(QObject *,const char *,QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument)' (compiling source file main.cpp)
1>x:\hmi_qt5\qt\msvc2017_x86\debug\include\qtcore\qobjectdefs.h(431): note: or       'bool QMetaObject::invokeMethod(QObject *,const char *,Qt::ConnectionType,QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument)' (compiling source file main.cpp)
1>x:\hmi_qt5\qt\msvc2017_x86\debug\include\qtcore\qobjectdefs.h(414): note: or       'bool QMetaObject::invokeMethod(QObject *,const char *,QGenericReturnArgument,QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument,QGenericArgument)' (compiling source file main.cpp)
1>d:\dev\project\project\main.cpp(49): note: while trying to match the argument list '(threadObj*, void (__thiscall QThread::* )(QThread::Priority), Qt::ConnectionType)'

提前致谢,

鲍勃

PS: 我确实有一个解决方法,可以通过使用仿函数或在 threadObj 中实现自定义插槽。 我问这个是因为我很好奇为什么这不起作用,因为我认为语法很好。

看来我找到了答案。 正如我最初预期的那样,问题不在 Qt 中,而是在 C++ 中。 当使用函数指针进行间接函数调用时,只能调用参数列表为空的函数。 (喜欢QThread::quit(void)) 当调用具有参数列表(包括默认参数)的函数时,它会隐式调用具有显式参数的函数。这在这里不起作用,因为函数指针中不能有参数。

正确的实现方式似乎是 lambda。

QMetaObject::invokeMethod(&threadObj, [&threadObj]() {threadObj.start(); }, Qt::QueuedConnection);

这样,你仍然可以在编译时检查语句的有效性。

鲍勃,你好

问题是 QThread::start 的参数的存在,虽然是默认的,并且 Qt 在 QMetaObject::invokeMethod 最重要的重载是用 const char *member 定义的方面被破坏了第二个参数。因此,使用这些重载之一,您可以直接使用它:

#include <functional>

#include <QtWidgets/QApplication>
#include <QtWidgets/QtWidgets>
#include <QtWidgets/QMainWindow>

#include <QThread>

int main(int argc, char *argv[]) {
    QThread threadObj;
    QMetaObject::invokeMethod(&threadObj, "start", Qt::QueuedConnection);

    QApplication this_application(argc, argv);
    return this_application.exec();
}

另一个解决方案是

QMetaObject::invokeMethod(&threadObj, std::bind(&QThread::start,std::ref(threadObj),QThread::InheritPriority), Qt::QueuedConnection);

这与 lambda 几乎相同,但恕我直言,意图更明确。