Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pattern to register metatypes in Qt

Tags:

c++

qt

Introduction

I've got a library, which registers a bunch of metatypes, illustrated by this code:


abstractfoobase.h

namespace foo {
    enum FooState { OK, MAYBE };
    class AbstractFooBase : public QObject {...};
}

Q_DECLARE_METATYPE(foo::FooState)

There is also a corresponding abstractfoobase.cpp, contents depending on what exactly is implemented in base class.


foousingclass.h:

namespace foo {

    class FooUsingClass : public AbstractFooBase {...};
}

Again there is corresponding foousingclass.cpp, which has method implementations etc.


Now, that Q_DECLARE_METATYPE enables the type for Qt template classes and QVariant. To enable using the type in queued signals and such, there also needs to be a corresponding call:

qRegisterMetaType<foo::FooState>();

Question

What is(are) the good place(s) to put the qRegisterMetaType call? I obviously don't want any expllicit initialization call from application code. The registrations must have happened after doing a foo::FooUsingClass *f = new foo::FooUsingClass();.

In Java I'd put this kind of code in a static initialization block. I can see several ways to do this in C++ too, but none of them seem particularily nice. For example, simply putting these to AbstractFooBase constructor will cause the registrations being called every time a subclass instance is created, which may be undesired overhead. So those who have done this, where did you put the qRegisterMetaType calls?

like image 307
hyde Avatar asked Nov 21 '13 07:11

hyde


1 Answers

I've recently discovered a simple solution, which works with static libraries as well.

It exploits the fact that qMetaTypeId<>() is used throughout Qt's meta type system. So, with an explicit template instantiation, we can enforce linkage to abstractfoobase.cpp (otherwise the linker might decide not to if there are no referenced symbols) and ensure that the type is registered statically at program startup:

abstractfoobase.h

#include <QMetaType>

namespace foo {
    enum FooState { OK, MAYBE };
}

Q_DECLARE_METATYPE(foo::FooState)

extern template int qMetaTypeId<foo::FooState>();

abstractfoobase.cpp

static const int kFooStateMetaTypeId = qRegisterMetaType<foo::FooState>();

template int qMetaTypeId<foo::FooState>();
like image 165
klaus triendl Avatar answered Sep 21 '22 23:09

klaus triendl