Search code examples
c++qtqthread

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


I have a console application with a QCoreApplication running the event loop in main(). Here i have an Object, that is a derivative of QThread, with run() implemented to do some testing. I want the thread to start upon starting my application, so I called

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

at the end of main().

Here is my Question: Why does this not compile?

Doing the same with QThread::quit works fine, yet QThread::exit does not. I presume it has something to do with the arguments for start and exit?`

The Compiler Error looks like this btw:

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)'

Thanks in Advance,

Bob

PS: I do have a workaround for this, either by using functors or implementing a custom slot in threadObj. I asked this because I'm curious as to why this doesn't work, since I think the syntax is fine.


Solution

  • The problem is the existence of a parameter of QThread::start, although defaulted, and Qt is broken in the aspect that the most important overloads of QMetaObject::invokeMethod are defined with const char *member as the 2nd parameter. So using one of those overloads you can use it directly:

    #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();
    }
    

    Another solution would be

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

    which is almost the same as a lambda, but IMHO clearer intention.