Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Emitting signals with custom types does not work

Tags:

qt

I'm trying to emit signal with custom type. Type is declared with Q_DECLARE_METATYPE and registered with qRegisterMetaType.

When I emit a signal, then I get next error to the output stream:

Type "MyType" has id:  1024 ; register status:  true
QObject::connect: Cannot queue arguments of type 'MyType' (Make sure 'MyType' is registered using qRegisterMetaType().)

Bug is reproducable only if a queued connection is used (when objects are in different threads or explicit Qt::QueuedConnection is used) and MyType is declared inside a namespace.

Sample code: MyType.h

#define SHOW_BUG

#ifdef SHOW_BUG

    namespace NS
    {
        struct MyType
        {
            int val;
        };
    }
    Q_DECLARE_METATYPE( NS::MyType );

#else

    struct MyType
    {
        int val;
    };
    Q_DECLARE_METATYPE( MyType );

#endif

MyClass.h:

#include "MyType.h"

namespace NS
{

    class MyClass
        : public QObject
    {
        Q_OBJECT
    public:
        MyClass( QObject *parent = NULL );
        ~MyClass();

    signals:
        void sendMyType( const MyType& tt );

    public slots:
        void invokeBug();
        void getMyType( const MyType& tt );
    };

}

MyClass.cpp

#include <QDebug>

namespace NS
{

    MyClass::MyClass(QObject *parent)
        : QObject(parent)
    {
        qRegisterMetaType< MyType >();
    }

    MyClass::~MyClass()
    {
    }

    void MyClass::invokeBug()
    {
        const int id = qMetaTypeId< MyType >();
        const bool test = QMetaType::isRegistered( id );
        qDebug() << "Type \"MyType\" has id: " << id << "; register status: " << test;

        MyType tt;
        tt.val = 42;
        emit sendMyType( tt );
    }

    void MyClass::getMyType( MyType const& tt )
    {
        qDebug() << "Slot fired: " << tt.val;
    }

}

Main.cpp

#include "MyClass.h"

int main(int argc, char *argv[])
{
    QCoreApplication a( argc, argv );

    NS::MyClass c1;
    NS::MyClass c2;
    QThread thread;
    thread.start();

    c2.moveToThread( &thread );

    QObject::connect( &c1, &NS::MyClass::sendMyType, &c2, &NS::MyClass::getMyType );
    QTimer::singleShot( 0, &c1, SLOT( invokeBug() ) );

    return a.exec();
}
like image 533
Dmitry Sazonov Avatar asked Jan 14 '14 17:01

Dmitry Sazonov


1 Answers

Got an answer from Qt team. Very strange usecases, but: signals must be declared with full namespace. This is a limitation of moc, coming from it not having a full-blown C++ parser.

So, this will work:

  class MyObject {
    ...
    // correct
    Q_SIGNAL void sendMyType( const NS::MyType& tt );
  };

But this won't:

namespace NS {
  ...
  class MyObject {
    ...
    // wrong
    Q_SIGNAL void sendMyType( const MyType& tt );
  };
}
like image 198
Dmitry Sazonov Avatar answered Oct 11 '22 11:10

Dmitry Sazonov