When is it mandatory to call qRegisterMetaType()?

Viewed 1021

I have studied the qt documentation of qRegisterMetaType() where it says that this function must be called before the corresponding type can be used in signal/slot mechanism. However I couldn't find any code example where this has to be done by hand.

This page states, that the registration is done automatically by the moc if it can determine that the type may be registered as meta-type. It looks like this is right, because I tested QSignalSpy, QObject::connect() (direct and queued connection) and QVariant - with just using Q_DECLARE_METATYPE(type) and none of them needed a explicit call to qRegisterMetaType to work.

So my question is: when do I have to call qRegisterMetaType(), because otherwise the code won't work?

1 Answers

The Qt docs say that Q_DECLARE_METATYPE is necessary in case one has a connect being a queued connection.

Adding a Q_DECLARE_METATYPE() makes the type known to all template based functions, including QVariant. Note that if you intend to use the type in queued signal and slot connections or in QObject's property system, you also have to call qRegisterMetaType() since the names are resolved at runtime.

For this I build a small testing app, that exemplifies the behavior.

Just try to remove the Q_DECLARE_METATYPE(Message) and watch the warnings and output change. In case of the normal connect the macro seems to be unnecessary.

main.cpp

#include <QApplication>
#include <QThread>
#include "MyHeaderView.h"

Q_DECLARE_METATYPE(Message);

int main(int argc, char **args)
{
    QApplication app(argc, args);
    {
        TestObject sender;
        TestObject receiver;
        QObject::connect(&sender, &TestObject::sendMessage, &receiver, &TestObject::onMessage);
        sender.emitMessage(1, 2);
    }


    // This requires Q_DECLARE_METATYPE(Message);
    QThread workerThread;
    TestObject sender2;
    TestObject receiver2;
    receiver2.moveToThread(&workerThread);
    workerThread.start();
    QObject::connect(&sender2, &TestObject::sendMessage, &receiver2, &TestObject::onMessage, Qt::ConnectionType::QueuedConnection);
    sender2.emitMessage(3, 4);

    app.exec();
}

TestObject.h

#pragma once

#include <QObject>
#include <QDebug>

struct Message
{
    int x;
    int y;
};

class TestObject : public QObject
{
    Q_OBJECT
public:
    void emitMessage(int x, int y) { emit sendMessage(Message{ x,y }); }
    signals:
        void sendMessage(const Message&);

public slots:
    void onMessage(const Message& m) { qDebug() << m.x << m.y; }
};
Related