Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Order of qRegisterMetaType calls affects program behaviour
Forum Updated to NodeBB v4.3 + New Features

Order of qRegisterMetaType calls affects program behaviour

Scheduled Pinned Locked Moved Solved General and Desktop
23 Posts 5 Posters 5.7k Views 4 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T Offline
    T Offline
    ttuna
    wrote on last edited by
    #11

    Even when there are no more suggestions in this forum someone may know where to find an answer to this problem ... ?!

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by SGaist
      #12

      Hi,

      Can you share somewhere a small compilable sample project that shows this behavior ?

      On a side note, you can ask questions also on the interest mailing list You'll find there Qt's developers/maintainers (this forum is more user oriented)

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      T 2 Replies Last reply
      0
      • SGaistS SGaist

        Hi,

        Can you share somewhere a small compilable sample project that shows this behavior ?

        On a side note, you can ask questions also on the interest mailing list You'll find there Qt's developers/maintainers (this forum is more user oriented)

        T Offline
        T Offline
        ttuna
        wrote on last edited by
        #13

        @SGaist
        I`ve created a github repo with a small example:
        https://github.com/ttuna/public.git

        1 Reply Last reply
        0
        • T Offline
          T Offline
          ttuna
          wrote on last edited by
          #14

          BTW: I'm using Qt 5.5.1 and MSVC2013_32bit compiler.

          1 Reply Last reply
          0
          • SGaistS SGaist

            Hi,

            Can you share somewhere a small compilable sample project that shows this behavior ?

            On a side note, you can ask questions also on the interest mailing list You'll find there Qt's developers/maintainers (this forum is more user oriented)

            T Offline
            T Offline
            ttuna
            wrote on last edited by
            #15

            @SGaist
            Any results from the example so far?

            kshegunovK 1 Reply Last reply
            0
            • T ttuna

              @SGaist
              Any results from the example so far?

              kshegunovK Offline
              kshegunovK Offline
              kshegunov
              Moderators
              wrote on last edited by kshegunov
              #16

              @ttuna
              Hello,
              It took the better half of an hour, but I found what your problem was. Before giving you the solution though I want to point out some things, please don't take offence even if they sound forceful.

              1. Don't use template needlessly!!! Why this:
              template<typename T> static QMetaProperty GetProperty(T& in_obj, QString in_name)
              

              is this not this:

              static QMetaProperty GetProperty(QObject & in_obj, QString in_name)
              

              There's no staticMetaObject without the Q_OBJECT macro.

              1. Don't, I repeat, do not derive from QApplication/QCoreApplication without a very, very good reason, unless you want to enter a world of hurt. It's a very bad idea, especially since you're not doing anything special.

              2. When registering meta types with the runtime give your own names only to the ones you've typedef-ed. E.g.:

              qRegisterMetaType<IntList>("IntList"); //< This is fine
              qRegisterMetaType<TestPropertyObject*>("TestPropertyObject*"); //< Don't do that!
              

              Instead use:

              qRegisterMetaType<IntList>("IntList");
              qRegisterMetaType<TestPropertyObject*>();
              
              1. I suggest putting these types of constructs - Q_DECLARE_FLAGS(JsonFileFlags, JFFlags) - in the global scope, not in the class.

              2. What's wrong with naming your enums directly?

              typedef enum {
                  PROPERTY_ACCESSOR_OPERATOR_UNKNOWN = 0,
                  // ...
              } CheckOperator;
              

              Are you coming from C? I don't see a reason to have an unnamed type and then typedef it.

              1. If you want to serialize your objects, consider writing operators for QTextStream/QDataStream instead of having functions like: PropertyPersistor::toFile(const QObject &, const QString &, const bool). Even if you use such functions, make them non-static, what's the point of giving the object as a parameter, you gain nothing.

              2. You have too many inline functions for my taste. If you want to have them inlined consider doing it by splitting the definition from the declaration and marking them as such explicitly, i.e.:

              // All this goes in the header
              class MyClass
              {
                  void myInlineFunction();
              };
              
              inline void MyClass::myInlineFunction()
              {
                  // ... Code
              }
              

              It makes for much easier reading and the class' interface is clearly visible.

              1. Just a remark - your project file is very confusing, my QtCreator seems to be unable to deduce that changes have been made, so I had to rebuild all times and times again. Perhaps it's like this because you're using MS Visual Studio, I don't know, but it looks strange.

              The solution

              bool RegisterTestAppl::init()
              {
                  // ...
                  id = qRegisterMetaType<IntList>("IntList");
                  id = qRegisterMetaType<TestPropertyObject *>();
                  // ...
              }
              
              static QVariantMap GetPropertyVariantMap(const QObject* in_obj, const QMetaObject* in_meta_obj, const bool in_recursive)
              {
                  // ...
                      if (meta_prop.type() >= QVariant::UserType && in_recursive == true)  {
                          int meta_prop_type = meta_prop.userType(); //< !!! QMetaProperty::userType() !!!
                          const QMetaObject* sub_meta_object = QMetaType::metaObjectForType(meta_prop_type);
                          // ...
                      }
              }
              

              Kind regards.

              Read and abide by the Qt Code of Conduct

              ? T 2 Replies Last reply
              1
              • kshegunovK kshegunov

                @ttuna
                Hello,
                It took the better half of an hour, but I found what your problem was. Before giving you the solution though I want to point out some things, please don't take offence even if they sound forceful.

                1. Don't use template needlessly!!! Why this:
                template<typename T> static QMetaProperty GetProperty(T& in_obj, QString in_name)
                

                is this not this:

                static QMetaProperty GetProperty(QObject & in_obj, QString in_name)
                

                There's no staticMetaObject without the Q_OBJECT macro.

                1. Don't, I repeat, do not derive from QApplication/QCoreApplication without a very, very good reason, unless you want to enter a world of hurt. It's a very bad idea, especially since you're not doing anything special.

                2. When registering meta types with the runtime give your own names only to the ones you've typedef-ed. E.g.:

                qRegisterMetaType<IntList>("IntList"); //< This is fine
                qRegisterMetaType<TestPropertyObject*>("TestPropertyObject*"); //< Don't do that!
                

                Instead use:

                qRegisterMetaType<IntList>("IntList");
                qRegisterMetaType<TestPropertyObject*>();
                
                1. I suggest putting these types of constructs - Q_DECLARE_FLAGS(JsonFileFlags, JFFlags) - in the global scope, not in the class.

                2. What's wrong with naming your enums directly?

                typedef enum {
                    PROPERTY_ACCESSOR_OPERATOR_UNKNOWN = 0,
                    // ...
                } CheckOperator;
                

                Are you coming from C? I don't see a reason to have an unnamed type and then typedef it.

                1. If you want to serialize your objects, consider writing operators for QTextStream/QDataStream instead of having functions like: PropertyPersistor::toFile(const QObject &, const QString &, const bool). Even if you use such functions, make them non-static, what's the point of giving the object as a parameter, you gain nothing.

                2. You have too many inline functions for my taste. If you want to have them inlined consider doing it by splitting the definition from the declaration and marking them as such explicitly, i.e.:

                // All this goes in the header
                class MyClass
                {
                    void myInlineFunction();
                };
                
                inline void MyClass::myInlineFunction()
                {
                    // ... Code
                }
                

                It makes for much easier reading and the class' interface is clearly visible.

                1. Just a remark - your project file is very confusing, my QtCreator seems to be unable to deduce that changes have been made, so I had to rebuild all times and times again. Perhaps it's like this because you're using MS Visual Studio, I don't know, but it looks strange.

                The solution

                bool RegisterTestAppl::init()
                {
                    // ...
                    id = qRegisterMetaType<IntList>("IntList");
                    id = qRegisterMetaType<TestPropertyObject *>();
                    // ...
                }
                
                static QVariantMap GetPropertyVariantMap(const QObject* in_obj, const QMetaObject* in_meta_obj, const bool in_recursive)
                {
                    // ...
                        if (meta_prop.type() >= QVariant::UserType && in_recursive == true)  {
                            int meta_prop_type = meta_prop.userType(); //< !!! QMetaProperty::userType() !!!
                            const QMetaObject* sub_meta_object = QMetaType::metaObjectForType(meta_prop_type);
                            // ...
                        }
                }
                

                Kind regards.

                ? Offline
                ? Offline
                A Former User
                wrote on last edited by
                #17

                @kshegunov Great posting. Could you please explain your point number 2? What's the problem with deriving from QApplication? Thanks in advance!

                kshegunovK 1 Reply Last reply
                0
                • ? A Former User

                  @kshegunov Great posting. Could you please explain your point number 2? What's the problem with deriving from QApplication? Thanks in advance!

                  kshegunovK Offline
                  kshegunovK Offline
                  kshegunov
                  Moderators
                  wrote on last edited by kshegunov
                  #18

                  @Wieland
                  Thanks. Well, I certainly overplayed this particular point, but the statement I believe is valid in principle. :)
                  QApplication is the root QObject of the program and its full initialization is required before anything can practically be done with anything else. It manages an insane amount of static variables and sets a static global pointer of itself when it initializes. I'm warning against it, because some time ago I had terrible time debugging a library that extended it and because of some subtle differences between the window and linux loaders it had trouble with a global variable. Long story short, I ended up with two instances of a global variable one in the application address space and one in the library address space (at the time I thought that impossible, but well, that's life). Sufficed to say that particular library was not the best of codes, but some caution is advised. Additionally, there's not much gain or need to extend the application, unless you're doing some specific low-level stuff. A hint that QApplication is not supposed to be inherited is the missing private object constructor, i.e.: QApplication::QApplication(QApplicationPrivate &) is nowhere to be found.

                  Kind regards.

                  Read and abide by the Qt Code of Conduct

                  1 Reply Last reply
                  0
                  • kshegunovK kshegunov

                    @ttuna
                    Hello,
                    It took the better half of an hour, but I found what your problem was. Before giving you the solution though I want to point out some things, please don't take offence even if they sound forceful.

                    1. Don't use template needlessly!!! Why this:
                    template<typename T> static QMetaProperty GetProperty(T& in_obj, QString in_name)
                    

                    is this not this:

                    static QMetaProperty GetProperty(QObject & in_obj, QString in_name)
                    

                    There's no staticMetaObject without the Q_OBJECT macro.

                    1. Don't, I repeat, do not derive from QApplication/QCoreApplication without a very, very good reason, unless you want to enter a world of hurt. It's a very bad idea, especially since you're not doing anything special.

                    2. When registering meta types with the runtime give your own names only to the ones you've typedef-ed. E.g.:

                    qRegisterMetaType<IntList>("IntList"); //< This is fine
                    qRegisterMetaType<TestPropertyObject*>("TestPropertyObject*"); //< Don't do that!
                    

                    Instead use:

                    qRegisterMetaType<IntList>("IntList");
                    qRegisterMetaType<TestPropertyObject*>();
                    
                    1. I suggest putting these types of constructs - Q_DECLARE_FLAGS(JsonFileFlags, JFFlags) - in the global scope, not in the class.

                    2. What's wrong with naming your enums directly?

                    typedef enum {
                        PROPERTY_ACCESSOR_OPERATOR_UNKNOWN = 0,
                        // ...
                    } CheckOperator;
                    

                    Are you coming from C? I don't see a reason to have an unnamed type and then typedef it.

                    1. If you want to serialize your objects, consider writing operators for QTextStream/QDataStream instead of having functions like: PropertyPersistor::toFile(const QObject &, const QString &, const bool). Even if you use such functions, make them non-static, what's the point of giving the object as a parameter, you gain nothing.

                    2. You have too many inline functions for my taste. If you want to have them inlined consider doing it by splitting the definition from the declaration and marking them as such explicitly, i.e.:

                    // All this goes in the header
                    class MyClass
                    {
                        void myInlineFunction();
                    };
                    
                    inline void MyClass::myInlineFunction()
                    {
                        // ... Code
                    }
                    

                    It makes for much easier reading and the class' interface is clearly visible.

                    1. Just a remark - your project file is very confusing, my QtCreator seems to be unable to deduce that changes have been made, so I had to rebuild all times and times again. Perhaps it's like this because you're using MS Visual Studio, I don't know, but it looks strange.

                    The solution

                    bool RegisterTestAppl::init()
                    {
                        // ...
                        id = qRegisterMetaType<IntList>("IntList");
                        id = qRegisterMetaType<TestPropertyObject *>();
                        // ...
                    }
                    
                    static QVariantMap GetPropertyVariantMap(const QObject* in_obj, const QMetaObject* in_meta_obj, const bool in_recursive)
                    {
                        // ...
                            if (meta_prop.type() >= QVariant::UserType && in_recursive == true)  {
                                int meta_prop_type = meta_prop.userType(); //< !!! QMetaProperty::userType() !!!
                                const QMetaObject* sub_meta_object = QMetaType::metaObjectForType(meta_prop_type);
                                // ...
                            }
                    }
                    

                    Kind regards.

                    T Offline
                    T Offline
                    ttuna
                    wrote on last edited by
                    #19

                    @kshegunov
                    First of all, i would like to thank you for your extensive work.

                    I should have mentioned that the code example is boiled down from a project with many programmers working on. If there are discrepancies like weird function templates etc. this is mostly the effect of cut down code fragments.

                    Concerning your objection against QApplication derivation you might be right. It's dangerous but i think it works great if you do it the right way (- though extending QApplication in a library is quite strange ;-)

                    Please could you explain your argumentation for 3.)?
                    I haven't found any explanations why i shouldn't use a name for TestPropertyObject* type registration.

                    BR

                    kshegunovK 1 Reply Last reply
                    0
                    • T ttuna

                      @kshegunov
                      First of all, i would like to thank you for your extensive work.

                      I should have mentioned that the code example is boiled down from a project with many programmers working on. If there are discrepancies like weird function templates etc. this is mostly the effect of cut down code fragments.

                      Concerning your objection against QApplication derivation you might be right. It's dangerous but i think it works great if you do it the right way (- though extending QApplication in a library is quite strange ;-)

                      Please could you explain your argumentation for 3.)?
                      I haven't found any explanations why i shouldn't use a name for TestPropertyObject* type registration.

                      BR

                      kshegunovK Offline
                      kshegunovK Offline
                      kshegunov
                      Moderators
                      wrote on last edited by
                      #20

                      @ttuna
                      Hello,
                      I'm glad I could help.

                      I should have mentioned that the code example is boiled down from a project with many programmers working on.

                      Yes, I gathered it's a group effort, however a style guide and "do-or-don't" document might be a good things to consider, especially for large projects where many people contribute.

                      If there are discrepancies like weird function templates etc. this is mostly the effect of cut down code fragments.

                      Well, the function templates are just not needed. How it's now, for each type that you pass to the function a new one will be generated in the binary, that is every QObject subclass will have its own function. No need for that, since all objects that have dynamic properties already extend from QObject, right?

                      (- though extending QApplication in a library is quite strange ;-)

                      To be honest, putting it in a library would be the singular reason I'd consider deriving from it. Otherwise just using main() does seem so much simpler and shorter (no extra class that is).

                      I haven't found any explanations why i shouldn't use a name for TestPropertyObject* type registration.

                      Actually this directly comes from the documentation of qRegisterMetaType. See the warning above the note near the end of the function description.

                      Kind regards.

                      Read and abide by the Qt Code of Conduct

                      T 1 Reply Last reply
                      1
                      • kshegunovK kshegunov

                        @ttuna
                        Hello,
                        I'm glad I could help.

                        I should have mentioned that the code example is boiled down from a project with many programmers working on.

                        Yes, I gathered it's a group effort, however a style guide and "do-or-don't" document might be a good things to consider, especially for large projects where many people contribute.

                        If there are discrepancies like weird function templates etc. this is mostly the effect of cut down code fragments.

                        Well, the function templates are just not needed. How it's now, for each type that you pass to the function a new one will be generated in the binary, that is every QObject subclass will have its own function. No need for that, since all objects that have dynamic properties already extend from QObject, right?

                        (- though extending QApplication in a library is quite strange ;-)

                        To be honest, putting it in a library would be the singular reason I'd consider deriving from it. Otherwise just using main() does seem so much simpler and shorter (no extra class that is).

                        I haven't found any explanations why i shouldn't use a name for TestPropertyObject* type registration.

                        Actually this directly comes from the documentation of qRegisterMetaType. See the warning above the note near the end of the function description.

                        Kind regards.

                        T Offline
                        T Offline
                        ttuna
                        wrote on last edited by
                        #21

                        @kshegunov
                        Thank you - I've overseen the note until now. But i think that this hint is not really meant literally.

                        If you see the text above:
                        "This function requires that T is a fully defined type at the point where the function is called. For pointer types, it also requires that the pointed to type is fully defined. Use Q_DECLARE_OPAQUE_POINTER() to be able to register pointers to forward declared types."

                        This would mean that

                        typedef TestPropertyObject* TestPropertyObjectPtr;
                        qRegisterMetaType<TestPropertyObjectPtr>("TestPropertyObjectPtr");
                        

                        would be ok even there is no difference to that former pointer type.

                        Nevertheless, your hint int meta_prop_type = meta_prop.userType(); //< !!! QMetaProperty::userType() !!! fixed the problem. So thank you again ...

                        BR

                        kshegunovK 1 Reply Last reply
                        0
                        • T ttuna

                          @kshegunov
                          Thank you - I've overseen the note until now. But i think that this hint is not really meant literally.

                          If you see the text above:
                          "This function requires that T is a fully defined type at the point where the function is called. For pointer types, it also requires that the pointed to type is fully defined. Use Q_DECLARE_OPAQUE_POINTER() to be able to register pointers to forward declared types."

                          This would mean that

                          typedef TestPropertyObject* TestPropertyObjectPtr;
                          qRegisterMetaType<TestPropertyObjectPtr>("TestPropertyObjectPtr");
                          

                          would be ok even there is no difference to that former pointer type.

                          Nevertheless, your hint int meta_prop_type = meta_prop.userType(); //< !!! QMetaProperty::userType() !!! fixed the problem. So thank you again ...

                          BR

                          kshegunovK Offline
                          kshegunovK Offline
                          kshegunov
                          Moderators
                          wrote on last edited by kshegunov
                          #22

                          @ttuna said:

                          Thank you - I've overseen the note until now.

                          Don't worry, I have been known on occasion to overlook notes in the documentation as well. It happens to all of us.

                          "This function requires that T is a fully defined type at the point where the function is called. For pointer types, it also requires that the pointed to type is fully defined. Use Q_DECLARE_OPAQUE_POINTER() to be able to register pointers to forward declared types."

                          Well, I don't pretend to know the meta-object system intimately, however I believe this is remarked because of the dynamic creation of objects capabilities. Probably it's needed when QMetaObject::newInstance is employed. So I'd stick to what the documentation says and do it like:

                          typedef TestPropertyObject * TestPropertyObjectPtr;
                          
                          qRegisterMetaType<TestPropertyObject *>();
                          qRegisterMetaType<TestPropertyObjectPtr>("TestPropertyObjectPtr");
                          

                          Or:

                          typedef TestPropertyObject * TestPropertyObjectPtr;
                          
                          qMetaTypeId<TestPropertyObject *>();  //< This calls qRegisterMetaType<TestPropertyObject *>(); internally
                          qRegisterMetaType<TestPropertyObjectPtr>("TestPropertyObjectPtr");
                          

                          Nevertheless, your hint int meta_prop_type = meta_prop.userType(); //< !!! QMetaProperty::userType() !!! fixed the problem. So thank you again ...

                          You're welcome. From what I could discern QMetaProperty::type returns QVariant::UserType for all user types, and that's why you need to call int QMetaProperty::userType() to get the correct type identifier.

                          Kind regards.

                          Read and abide by the Qt Code of Conduct

                          1 Reply Last reply
                          1
                          • SGaistS Offline
                            SGaistS Offline
                            SGaist
                            Lifetime Qt Champion
                            wrote on last edited by
                            #23

                            @kshegunov was faster than me :) But basically yes, the example was a bit over-engineered.

                            Note that with Qt 5, there's no need to give a name at all when calling qRegisterMetaType unless you are registering a typedefed class.

                            Interested in AI ? www.idiap.ch
                            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                            1 Reply Last reply
                            0

                            • Login

                            • Login or register to search.
                            • First post
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • Users
                            • Groups
                            • Search
                            • Get Qt Extensions
                            • Unsolved