c++qttypedefqt-signalsqmetatype

Registering aliases types of custom MetaType in Qt


I have a simple custom type XyztReal and its aliases in my datamodel.h header file:

#ifndef IMUCONTROLLERDATAMODEL_H
#define IMUCONTROLLERDATAMODEL_H

#include <QMetaType>

namespace imu_controller {
namespace data {

// some code

struct __attribute__((__packed__)) XyztReal {
    qreal x ;
    qreal y ;
    qreal z ;
    qreal ts;
};

typedef XyztReal GyrReal;
typedef XyztReal AccReal;
typedef XyztReal MagReal;

void registerTypes();

}
}

Q_DECLARE_METATYPE(imu_controller::data::XyztReal)

#endif // IMUCONTROLLERDATAMODEL_H

and registering function in source datamodel.cpp:

void registerTypes()
{
    qRegisterMetaType<XyztReal>("XyztReal");   // or qRegisterMetaType<XyztReal>();
    qRegisterMetaType<GyrReal >("GyrReal" );
    qRegisterMetaType<AccReal >("AccReal" );
    qRegisterMetaType<MagReal >("MagReal" );
}

So i call this function in proper place in programm and try to connect signals/slots of some objects in different thread like this:

Qt::ConnectionType ct = static_cast<Qt::ConnectionType>(Qt::BlockingQueuedConnection | Qt::UniqueConnection);
connect(data_ctrl, &imu_controller::DataController::gyrRealReady, this, &MainWindow::someSlot, ct);

where signal/slot has imu_controller::data::GyrReal and imu_controller::data::XyztReal arguments type respectively, or:

Qt::ConnectionType ct = static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::UniqueConnection);
connect(data_ctrl, &imu_controller::DataController::gyrRealReady, this, &MainWindow::onImuGyrRealReceived, ct);

where signal/slot has imu_controller::data::GyrReal arguments type both, But program does not works and debuger prints:

QObject::connect: Cannot queue arguments of type 'imu_controller::data::GyrReal' (Make sure 'imu_controller::data::GyrReal' is registered using qRegisterMetaType().)

for all XyztReal aliases types.

Important: The program works if imu_controller::DataController class signals type changed to XyztReal types!

PS: I think the problem at types registering. I read qt docs and several topics but i don't found a solution or any examples.


Solution

  • As far as I understand, the const char * typeName argument of qRegisterMetaType is quite necessary here. Also it takes consistency in terms of namespaces.

    Say you have this signal in your DataController class:

    signals:
        void some_signal(data::AccReal);
    

    Since the class lies in the imu_controller namespace, you just add the data namespace before the argument class name.

    Now, in your registerTypes function, it should be registered like this:

    qRegisterMetaType<AccReal >("data::AccReal");
    

    In other words, the typeName string must match exactly the type of the signal argument as it is written there.

    It looks like one can register a type more than once, specifying different typenames, i.e.

    qRegisterMetaType<AccReal >("AccReal");
    qRegisterMetaType<AccReal >("data::AccReal");
    qRegisterMetaType<AccReal >("imu_controller::data::AccReal");
    

    Curiously, if you have a

    using WhatEver = imu_controller::data::AccReal;
    

    somewhere, then you can have

    signals:
        void some_signal(WhatEver);
    

    as long as you have

     qRegisterMetaType<AccReal >("WhatEver");
    

    To summarize things up, your register function could be like:

    QString aliases[] = {"XyztReal", "GyrReal", "AccReal", "MagReal" };
    for(auto a : aliases)
    {
        qRegisterMetaType<XyztReal>(a.toLatin1());
    
        a.prepend("data::");
        qRegisterMetaType<XyztReal>(a.toLatin1());
    
        a.prepend("imu_controller::");
        qRegisterMetaType<XyztReal>(a.toLatin1());
    }
    

    i.e. you can register XyztReal several times, one for each possible alias with every possible combination of namespaces.