Search code examples
c++qtenumsqmetaobjectqmetatype

Is Qt's meta system really that tedious?


I would like to use Qt's reflection mechanism since C++ lacks of this feature. It seems to work, but calling all the macros and helper functions is very tedious. For example to register an enum as a proper meta type I had to go through all the following steps:

  1. Declare an enum inside of a wrapper class that contains the Q_GADGET macro.
  2. Register the enum using the Q_ENUM macro just after that.
  3. Register the class containing the enum: Q_DECLARE_METATYPE(MyClass)
  4. Call qRegisterMetaType<..>() for the type of the wrapping class and for each declared enum.

Now I know that some of the steps can be omitted if part of the full functionality is not required. But that is not what I am looking for, I need to use enums within signals and I need to be able to get the the meta method of a signal and query it for it's parameters type.

But still I can't help thinking that there must be a better/simpler way to do this.


Solution

  • Unfortunately, you can't do less than that.

    • Q_GADGET (or Q_OBJECT, for QObject subclasses) means "generate meta-object information for this class".
    • Q_ENUM means "generate meta-enum information for this particular enum". Now one might argue that all (public?) enumerations in a registered class should be also automatically registered. But since this has a cost (binary size), and we use C++, we don't want to pay for enums we're never going to use in the meta-object system, so it's opt-in.
    • Q_DECLARE_METATYPE (not needed on the enum itself if you're using Q_ENUM; not needed in general, in your scenario) enables the type to be used inside QVariants (Qt's C++98, RTTI-less incarnation of C++17's std::any). Whether you want this or not depends on the type. I would say that all "value types" should have it, but again, this generates extra code that you may not want to pay for. Also, this really applies to "value types" only -- this registration requires the type to have public default constructor, public copy constructor, public copy assignment, public destructor. If you've got a class which does not have these, you can't use this macro => you can't wrap it in a QVariant.
    • qRegisterMetaType registers the aforementioned constructors/destructors in a table at runtime, enabling you to have an unique id for the type (required if you want to identify types in method signatures), dynamically create or destroy instances of the type (required, amongst other things, to implement queued connections: Qt needs a generic way to copy the signal's arguments into an event to be sent to the target thread, and destroy such arguments later), use the Q_PROPERTY subsystem.

    Depending on what exactly you need to do you need a subset of all of this.