Emitting signals with custom types does not work

qt

Solution

The code below illustrates the failure, and the solution. It works on both Qt 4 and Qt 5.

Now we fail 
QObject::connect: No such signal NS::Object::badSignal(NS::MyType) in ../metatype-21119397/main.cpp:32
Now we succeed 
Successful slot call 1 
#include <QCoreApplication>
#include <QDebug>

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

    class Object : public QObject {
        Q_OBJECT
    public:
        Q_SIGNAL void goodSignal(const NS::MyType &);
        Q_SIGNAL void badSignal(const MyType &);
        Q_SLOT void slot(const NS::MyType & x) {
            qDebug() << "Successful slot call" << x.val;
        }
    };
}
Q_DECLARE_METATYPE(NS::MyType)

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    NS::Object src, dst;
    qRegisterMetaType<NS::MyType>();

    qDebug() << "Now we fail";
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
    QObject::connect(&src, &NS::Object::badSignal, &dst, &NS::Object::slot, Qt::QueuedConnection);
#else
    dst.connect(&src, SIGNAL(badSignal(NS::MyType)), SLOT(slot(NS::MyType)), Qt::QueuedConnection);
#endif
    emit src.goodSignal(NS::MyType(1));

    qDebug() << "Now we succeed";
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
    QObject::connect(&src, &NS::Object::goodSignal, &dst, &NS::Object::slot, Qt::QueuedConnection);
#else
    dst.connect(&src, SIGNAL(goodSignal(NS::MyType)), SLOT(slot(NS::MyType)), Qt::QueuedConnection);
#endif
    emit src.goodSignal(NS::MyType(1));

    return a.exec();
}

#include "main.moc"

Problem

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

Original source