New in Qt 5.5: Q_ENUM and the C++ tricks behind it

Qt 5.5 was just released and with it comes a new Q_ENUM macro, a better alternative to the now deprecated Q_ENUMS (with S).

In this blog post, I will discuss this new Qt 5.5 feature; What it does, and how I implemented it.
If you are not interested by the implementation details, skip to the conclusion to see what you can do in Qt 5.5 with Q_ENUM.

The problem

In order to better understand the problem it solves, let us look at this typical sample code using Q_ENUMS
as it already could have been written with Qt 4.0.

That has been working fine since Qt 4.0, but you have to manually write this operator and it is
a lot of code that is somehow error prone. Most of Qt's own enumerations did not even have such operator.

The Solution

I wanted this to be automatic. The problem is that we had no way to get the QMetaObject of the enclosed
QObject (or Q_GADGET) associated with a given enumeration.
We also need the name of the enumeration to be passed as an argument to QMetaObject::indexOfEnumerator.
Let us suppose we have some magic functions that would do exactly that. (We will see later how to make them):

Argument dependent lookup (ADL) will find the right overload for
qt_getEnumMetaObject and qt_getEnumName, and this function will work.
The problem is that this template will match any type, even the ones that are not enumerations or that are not registered with Q_ENUM for which qt_getEnumMetaObject(enum) would not compile.
We have to use SFINAE (substitution failure is not an error)
to enable this operator only if qt_getEnumMetaObject(enum) compiles:

So now it all boils down to how to implement the Q_ENUM macro to declare this qt_getEnumMetaObject.
We need to implement the function qt_getEnumMetaObject in the same namespace as the class. Yet, the macro is used within the class. How can we implement the function in the class? Perhaps using some static function or some template magic? No! We are going to use a friend function. Indeed, it is possible to define a function in a friend declaration. As an illustration:

namespaceABC {
classFooBar {
friendintfoo() { return456; }
};
}

foo is in the namespace ABC (or the global namespace if FooBar was not in a namespace).
But the interesting fact is that in the body of that function, the lookup is done within the class's scope:

This uses the staticMetaObject of the class (as declared in the Q_OBJECT macro).
The function can just be called by getFooBarMetaObject();
(without the FooBar:: that would be required if it was a static function instead of a friend).
With that we can now construct the Q_ENUM macro:

Each instance of this macro will create a new overload of the functions for the given enum type.
However, this needs the ENUM type to be declared when we declare the function.
Therefore we need to put the Q_ENUM macro after the enum declaration.
This also permits only one enum per macro while Q_ENUMS could have several.

(moc will still interpret the Q_ENUM macro like the old Q_ENUMS macro
and generate the same data.)

Using this, I also introduced a new static function QMetaEnum::fromType<T>() which let you easily get a
QMetaEnum for a given type. This is how it is implemented:

We can also integrate it with QMetaType to register this type automatically and register the
correspding meta object to the metatype system.
From that, we can use this information in QVariant to convert from a string or to a string.