PDA

View Full Version : Q_DECLARE_METATYPE vs qRegisterMetaType for non global namespace classes (QTest)



topoden
18th December 2009, 18:22
Hello guys,

I'm trying to test my class which emits a signal where one of parameters is my custom class:



namespace MyNamespace
{

struct MyData
{
};

class MyClass : public QObject
{
Q_OBJECT

public:
...
signals:
void mySignal(const MyData &);
};

}


So my testing code looks like:



Q_DECLARE_METATYPE(MyNamespace::MyData)

namespace MyNamespace
{

class MyClassTest : public QObject
{
Q_OBJECT

public slots:
void initTestCase()
{
qRegisterMetaType<MyNamespace::MyData>("MyData"); // case 1
//qRegisterMetaType<MyNamespace::MyData>("MyNamespace::MyData"); // case 2
}

private slots:

void test_mySignal()
{
...
QSignalSpy mySignalSpy(my_object, SIGNAL(mySignal(const MyData &)));

MyData expected_data;
... // code which triggers the signal

QCOMPARE(mySignalSpy.count(), 1); // Works

QList<QVariant> mySignalResult = mySignalSpy.takeFirst();
MyData arrived_data = mySignalResult.at(0).value<MyNamespace::MyData>(); // Here I get empty data

QCOMPARE(arrived_data, expected_data);
}
};
}


1. I've put Q_DECLARE_METATYPE in order to have MyData to / from QVariant functionality working. And the following code works properly:


MyData data;
QVariant data_variant = QVariant::fromValue<MyData>(data);
MyData data_new = data_variant.value<MyData)();


2. I've put qRegisterMetaType in order to have signals / slots with MyData parameters working.

As you see I have two cases of qRegisterMetaType usage: the first case seems to make signals / slots working, but I get empty MyData from the mySignalResult; the second case leads to warning "Dont't know how to hande 'MyData'" emitted by QSignalSpy.

So the question is - what I'm doing wrong ?

topoden
18th December 2009, 19:01
As I understand here I have type names conflict:



Q_DECLARE_METATYPE(MyNamespace::MyData) // registers the type with "MyNamespace::MyData" name

qRegisterMetaType<MyNamespace::MyData>("MyData") // registers the same type with "MyData" name


The signal I have expects the type to be registered with "MyData" name. So if I change declaration of the signal to be:



namespace MyNamespace
{

class MyClass : public QObject
{
Q_OBJECT

public:
...
signals:
void mySignal(const MyNamespace::MyData &);
};
}



Then everything starts working.

The question now is, why do I have to fully qualify the class in the signal declaration ? The class declaration (where the signal is declared) is located in the same namespace.

Could someone please explain me the full logic covered behind this ?

j_kubik
21st April 2013, 02:05
The reason for this behavior might be caused by the fact that runtime signal/slot connections are checked by string manipulation - both Q_DECLARE_METATYPE, SIGNAL, SLOT macros and 'moc' are (among other things) converting type-names to text and pass it along into qt's machinery. For C++ compiler changing function declaration to fully qualified parameter shouldn't make any difference, but probably 'moc' parsing file has some problems figuring it out. For some time I was wondering how smart this Meta-Object-Compiler really is, and how deeply it inspects my code - clearly some more investigation is needed.

Apart from that, how do you connect your signals? if you wrote your code manually using qt-creator then it's likely that autocompletion led you in each case (signal with and without full name) to slightly different 'connect' lines, which could also make some difference.

anda_skoa
23rd April 2013, 15:38
Additional to having the fully qualified name in the signal and slot declarations, I would just call qRegisterMetaType<MyNamespace::MyType>(), i.e. without function argument and let Qt figure out the most appropriate string.

Also, Q_DECLARE_METATYPE(MyNamespace::MyType) should be in the header declaring MyType so that you don't have to repeat it all over again and again.

In normal applications you usually won't need qRegisterMetaType(), here in the unittest you need it for QSignalSpy

Cheers,
_