QMetaEnum Magic – Serializing C++ Enums – Take 2

This post was imported from blogger, to see the original, likely better-formatted post see kalebpederson.blogspot.com.

>

A few posts ago I described two methods of serializing C++ enums. Of these, method 2 serialized the Qt::Key enum. The approach, however, relied on some behind the scenes magic that I wasn’t fully aware of nor did I fully document. This approach remedies that and describes in full the requirements for serializing C++ enums.

Method 2 – Reevaluated

The goal for this method is to take an enum called MyKey in the MyNS namespace and serialize it. In brief, the code for that looks like the following:

namespace MyNS{    enum MyKey {        MyKey_Return = 0,        MyKey_Enter = 1        };}

Since we want Qt to be able to serialize the above enum, it needs to know about the enum, so we’re going to need Q_ENUMS(MyKey). But unless moc sees a Q_OBJECT or Q_GADGET macro, our Q_ENUMS macro will result in a compilation error. To get around this, we need to convince moc to process the file as if it were a class. We can do that by adding some preprocessor defines:

#ifndef Q_MOC_RUNnamespace MyNS#elseclass MyNS#endif{#if defined(Q_MOC_RUN)    Q_GADGET    Q_ENUMS(MyKey)public:#endif    enum MyKey {        MyKey_Return = 0,        MyKey_Enter = 1    };}

At this point we’ve convinced moc to look at and process the file, but that alone isn’t enough. The code that moc generates assumes that a const staticMetaObject has been declared, but at this point one hasn’t been declared. Although some compilers will let us get away with this, we’ll declare it as follows:

    // ... continuing at the enum    enum MyKey {        MyKey_Return = 0,        MyKey_Enter = 1    };    extern const QMetaObject staticMetaObject;}

With that in place, we’re ready to serialize the enum. The first step is to get a copy of the QMetaEnum object. We do so by accessing the static reference directly and then calling indexOfEnumerator to get the appropriate index:

    // get the QMetaEnum object    const QMetaObject &mo = MyNS::staticMetaObject;    int enum_index = mo.indexOfEnumerator("MyKey");    QMetaEnum metaEnum = mo.enumerator(enum_index);

With the QMetaEnum instance in hand, we can now serialize the enum as demonstrated in my prior post:

    // convert to a string    MyNS::MyKey key = MyNS::MyKey_Return;    QByteArray str = metaEnum.valueToKey(key);    qDebug() << "Value as str:" << str;

    // convert from a string    int value = metaEnum.keyToValue("MyKey_Enter");    key = static_cast(value);    qDebug() << "key is MyKey_Enter? : " << (key == MyNS::MyKey_Enter);

With all the above in place, we’ve used a bit of magic to trick moc into thinking MyNS was a class. This causes moc to generate a MyNS::staticMetaObject instance and store the necessary serialization meta data. With everything in place, we get the following output:

Value as str: "MyKey_Return" key is MyKey_Enter? :  true 

References:

Related posts:

  1. QMetaEnum Magic – Serializing C++ enum’s

No comments yet.

Leave a Reply