Q_DECLARE_METATYPE for template class



  • I just wrote a little templated container class. Something like this:

    @
    template <typename T> class Container: public ContainerBase
    {
    ......
    T data;
    };
    @

    I need to register all instances of that template automatically to meta type system and binary data streams. I was able to implement automatic creation and registration of data streams. It was also no big issue to call qRegisterMetaType() automatically.

    However Q_DECLARE_METATYPE() is a bit more complicated.

    Using the macro directly turned out to be impossible. So I played around, copied the original macro and adapted it a bit:

    @
    template <typename T> struct QMetaTypeId<Container<T>>
    {
    enum { Defined = 1 };
    static int qt_metatype_id()
    {
    static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
    if (const int id = metatype_id.loadAcquire()) return id;
    const int newId = qRegisterMetaType<Container<T>>(typeid(Container<T>).name(), reinterpret_cast<Container<T>*>(quintptr(-1)));
    metatype_id.storeRelease(newId);
    return newId;
    }
    };
    @

    This works fine. But I would like to avoid copying Qt internals.

    Is there any solution for that problem that involves official Qt API only?



  • Q_DECLARE_METATYPE_TEMPLATE_1ARG(Container)



  • Thanks for your answer! That macro looks very promising. I replaced my snippet by

    @ Q_DECLARE_METATYPE_TEMPLATE_1ARG(Container) @

    but I get the usual static assert

    @ "Type is not registered, please use the Q_DECLARE_METATYPE macro to make it known to Qt's meta-object system" @

    However I do not understand why. I would have expected that it works.



  • Here I tested and it works, even I tested the metatype ids for some instances and looks ok: are you sure that error comes from where you call the macro definition for templates?

    and one more issue: you can still improve your workaround to make it completely generic ... for this have a look at qt code how they use strays "" ... I'm not good at this but I tested like there and it works



  • Yes, I checked the "Type is not registered" error. It definitely corresponds to the missing container declaration.

    BTW that Container and ContainerBase class is not a QList or QSet or something. I should have mentioned that these are custom classes holding a single data instance. They are not similar to the Qt container.

    I did some tests. This one works too (however this isn't what I want to do):

    @Q_DECLARE_METATYPE(Container<ConcreteType>) @

    I also tried to declare the contained type first before declaring the container:

    @Q_DECLARE_METATYPE(ConcreteType)
    Q_DECLARE_METATYPE_TEMPLATE_1ARG(Container); @

    This gives me a different error "value_type is not an element of Container<T>" in this line of qmetatype.h:

    @template<typename T, bool = QMetaTypeId2<typename T::value_type>::Defined> @

    Then I added

    @typedef T value_type; @

    to my Container class. Now I get an error about a missing iterator.

    My impressions is that there are lot of concrete features that are expected being implemented in the provided container class. I can't fulfil all of them (especially iterators). Is that macro specialized for Qt containers and alike?

    Any ideas on this?



  • how I tested here:

    in simple main window app, in mainwindow.h:

    @
    ...
    class ContainerBase
    {

    };

    template <class T> class Container: public ContainerBase
    {

    T data;
    };

    Q_DECLARE_METATYPE_TEMPLATE_1ARG(Container)
    @

    what is ConcreteType, a built in one?



  • bq. This gives me a different error “value_type is not an element of Container<T>” in this line of qmetatype.h:
    template<typename T, bool = QMetaTypeId2<typename T::value_type>::Defined>

    this line does not exist here! :) I use qt 5.1.1 mingw



  • I used an enum class as concrete type and I am using Qt5.2.0 beta here.
    How did you involve QVariant?

    This is a minimum example that breaks compilation when used in one of projects headers:

    @
    template <class T> class Container
    {
    };

    Q_DECLARE_METATYPE_TEMPLATE_1ARG(Container)

    inline void Test()
    {
    QVariant x = QVariant::fromValue(Container<int>());
    }
    @



  • it gives no error here ...

    @Container<int> y = x.value< Container<int> >();@

    returns the correctly too

    shall I understand that Q_DECLARE_METATYPE_TEMPLATE_1ARG is working now?



  • No, it does NOT work. I also tried the code in one if the Qt examples to make sure there are no collisions in my custom project.

    Adding the following code:

    @
    #include <QVariant>

    template <class T> class Container
    {
    };

    Q_DECLARE_METATYPE_TEMPLATE_1ARG(Container)

    inline void Test()
    {
    QVariant x = QVariant::fromValue(Container<int>());
    }

    @

    to the bottom of the tabdialog.h header of TabWidget example returns errors on building:

    @
    C:\Qt\Qt5.2.0\5.2.0-beta1\msvc2012\include\QtCore\qmetatype.h:1372: Fehler:C2039: 'value_type': Ist kein Element von 'Container<T>'
    with
    [
    T=int
    ]
    C:\Qt\Qt5.2.0\5.2.0-beta1\msvc2012\include\QtCore/qmetatype.h(1578): Siehe Verweis auf die Instanziierung der gerade kompilierten Klassen-template "QtPrivate::SequentialContainerConverterHelper<T>".
    with
    [
    T=Container<int>
    ]

    ..... and a lot more

    @

    If it works for you I suppose this is a Qt 5.2.0 beta problem. I am using 5.2.0 beta, VS2012, ANGLE, 32 Bit.



  • I did this test with Qt5.1.1 (VS2012, ANGLE, 32 Bit) and it worked.

    I also did it with Qt5.2.0-beta1 and it failed.

    So I can definitely confirm that there is some strange issue with Qt5.2.0-beta1 (VS2012, ANGLE, 32 Bit).


  • Lifetime Qt Champion

    Hi,

    It sounds like a regression (I may be wrong though), there has been a lot of work on QMetatype lately. Can you open a bug report so it might get fixed before 5.2 official release ?



  • bq. I did this test with Qt5.1.1 (VS2012, ANGLE, 32 Bit) and it worked.
    I also did it with Qt5.2.0-beta1 and it failed.
    So I can definitely confirm that there is some strange issue with Qt5.2.0-beta1 (VS2012, ANGLE, 32 Bit).

    I can confirm these tests too, but I want to do one more with Qt 5.2.0-beta1 with mingw



  • I found a solution for Qt 5.2.0-beta1:

    @class ContainerBase: public QString /!!!inherits a core class which is compatible with the new meta type system!!!/
    {

    };

    template <class T> class Container: public ContainerBase
    {
    T data;

    };

    Q_DECLARE_METATYPE_TEMPLATE_1ARG(Container)@





  • Update:

    According to the report (see above), the Q_DECLARE_METATYPE_TEMPLATE_1ARG in Qt5 seem to work as expected.

    Unfortunately they do not intend to support registering template types (using a new public macro). So I will need to stick to my nasty workaround :-(

    Anyway thanks for your help!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.