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. Type Erasure In QModelIndex
Forum Updated to NodeBB v4.3 + New Features

Type Erasure In QModelIndex

Scheduled Pinned Locked Moved Unsolved General and Desktop
14 Posts 6 Posters 811 Views 5 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.
  • Christian EhrlicherC Offline
    Christian EhrlicherC Offline
    Christian Ehrlicher
    Lifetime Qt Champion
    wrote on last edited by
    #5

    Then derive both from a common virtual base class.

    Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
    Visit the Qt Academy at https://academy.qt.io/catalog

    1 Reply Last reply
    1
    • C crow

      @Christian-Ehrlicher a void* pinter delete type info, If pass the struct pointer after type erasure, It can not find a suitable time to release passed struct pointer.

      class File
      {
          const char* GetData() const ...
      }
      
      class Folder
      {
          const char* GetName() const ...
      
         std::set<File*> fileset;
         std::set<Folder*> folder;
      }
      

      just like above, wo want to show the folder file like real file struct. unfortunately, only a void* can not identify it is a folder or a file because they have different base class. and there are many time the data and the hierarchies is from other module so wo can change it. but if use QVariant we can add type info in to QVariant.
      actually I meet this problem in my work, void* pointer can not identify what actual type is but QVariant can. I have to wrtite ugly and complex code to show this hierarchies
      I think this change is tiny and have no bad effect for dev and runtime efficiency, It can improve QAbstrauctItemModel`s compatibility

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

      Any particular reason for you not to leverage runtime polymorphism and use dynamic_cast?

      Read and abide by the Qt Code of Conduct

      C 1 Reply Last reply
      0
      • kshegunovK kshegunov

        Any particular reason for you not to leverage runtime polymorphism and use dynamic_cast?

        C Offline
        C Offline
        crow
        wrote on last edited by
        #7

        @kshegunov said in Type Erasure In QModelIndex:

        Any particular reason for you not to leverage runtime polymorphism and use dynamic_cast?

        actually i use dynamic_cast to solve thi problem for now, but there are too many problem with virtual inherit base class, multi inherit and diamond inherit. and i can NOT modify data struct hierarchies because it not write by me. Before use dynamic_cast you also have to change void* to a virtual class pointer but some time the real type is not a virtual class

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

          Hi,

          Can you show how you implemented your model ? It looks like you may be taking the problem from the wrong end.

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

          C 1 Reply Last reply
          1
          • SGaistS SGaist

            Hi,

            Can you show how you implemented your model ? It looks like you may be taking the problem from the wrong end.

            C Offline
            C Offline
            crow
            wrote on last edited by
            #9

            @SGaist said in Type Erasure In QModelIndex:

            wrong end

            the data structure and hierarchy like below
            THIS DATA STRUCTURE DEFINE IN OUTER MODULE LIKE DYNMAIC LIBRARY AND MAINTAIN BY OUTER,
            NO WAY TO MODIFY OR OPERATE

            root(Group*)
            |
            |---props--|--prop
            |          |--prop
            |          |--prop
            |          |-- ...
            |
            |---group--|--props--|--prop
            |          |         |--prop
            |          |         |-- ...
            |          |
            |          |--item------props--|--prop
            |          |--item---+         |--prop
            |          |--item---+         |--prop
            |                              |--prop
            |---group--+                   |-- ...
            |---group--+
            |--- ...
            |---item---|--props--|--prop   
            |---item             |--prop
            |---item             |--prop
            |---item
            |--- ...
            
            
            class Prop // base class
            {
                (some property info)
            };
            
            class Item // base class, can inherited by other class but not Prop or Group
            {
                (some data)
                std::vector<Prop> props;
            };
            
            class Group // base class
            {
                std::vector<Prop> props;
                std::set<Group*> groups;
                std::set<Item*> items
            };
            

            my model implement

            
            // its hard to implement with 2 num 1 void* and above data structure
            bool IsGroup(const ModelIndex&) { ... }
            bool IsProps(const ModelIndex&) { ... }
            
            QModelIndex MyModel::index(int row, int column, const QModelIndex& parent) const
            {
                if (!hasIndex(row, column, parent))
                    return QModelIndex();
            
                if ( IsGroup(parent) )
                {
                    // return a props pointer or Group* or Item* 
                    ...
                }
                else if( IsProps(parent) )
                {
                    // return pointer in std::vector data(), not safe
                    ...
                }
                else // parentitem is Item*
                {
                    // return props pointer
                }
            
                return QModelIndex();
            }
            
            QModelIndex MyModel::parent(const QModelIndex& index) const
            {
                // is hard to implement if actual data struct's  inclusion relation is one-way just with a row num, a column num and a void * 
                // so i traversal from root to find what it real parent
            }
            int MyModel::rowCount(const QModelIndex& parent) const
            {
                if (parent.column() > 0)
                    return 0;
            
                if ( IsGroup(parentItem) )
                {
                    void* parentItem = parent.isValid() ? parent.internalPointer() : root;
                    Group* g = static_cast<Group*>(parentItem);
                    return 1 + g->groups.size() + g->items.size();
                }
                else if( IsProps(parentItem) )
                {
                    auto props =static_cast<std::vector<Prop>* >(parent.internalPointer());
                    return props->size();
                }
            
                return 1;
            }
            

            Its not complete code, but I think its clearly.
            I want to pass some associate info to QModelIndex, and it would release when QModelIndex release, void* can not do this. QVariant or share_ptr... can do this and not destory original Qt design.
            Privade other solution is also welcome, I just want to solute this problem elegantly
            Thanks for your help

            1 Reply Last reply
            0
            • C crow

              @kshegunov said in Type Erasure In QModelIndex:

              Any particular reason for you not to leverage runtime polymorphism and use dynamic_cast?

              actually i use dynamic_cast to solve thi problem for now, but there are too many problem with virtual inherit base class, multi inherit and diamond inherit. and i can NOT modify data struct hierarchies because it not write by me. Before use dynamic_cast you also have to change void* to a virtual class pointer but some time the real type is not a virtual class

              S Offline
              S Offline
              SimonSchroeder
              wrote on last edited by
              #10

              @crow said in Type Erasure In QModelIndex:

              actually i use dynamic_cast to solve thi problem for now, but there are too many problem with virtual inherit base class, multi inherit and diamond inherit. and i can NOT modify data struct hierarchies because it not write by me. Before use dynamic_cast you also have to change void* to a virtual class pointer but some time the real type is not a virtual class

              One thing that comes to mind is the Curiously Recurring Template Pattern (CRTP). It is not the most elegant solution, but I guess it helps when you cannot change the original classes because they are part of a library.

              Let's assume you have some library classes:

              class SomeLibClassA;
              class SomeLibClassB;
              ... // maybe more classes
              

              The dynamic_cast needs to be replaced with switch over enums later on. So, define your enum:

              enum class ClassType { UNKNOWN, SOME_LIB_CLASS_A, SOME_LIB_CLASS_B, ...}; // add enums for all your classes here
              

              For convenience I suggest a comman base class for all CRTP classes:

              class Base
              {
              public:
                  ClassType type = ClassType::UNKNOWN;
              };
              

              And now for the CRTP template:

              template <class T>
              class CRTPBase : public Base
              {
              public:
                  T *object;
              };
              

              This can now be used to create wrapper classes for the library classes:

              class SomeLibClassAWrapper : public CRTPBase<SomeLibClassA>
              {
              public:
                  SomeLibClassAWrapper(SomeLibClassA *o) : type(ClassType::SOME_LIB_CLASS_A), object(o) {}
              };
              
              class SomeLibClassBWrapper : public CRTPBase<SomeLibClassB>
              {
              public:
                  SomeLibClassBWrapper(SomeLibClassB *o) : type(ClassType::SOME_LIB_CLASS_B), object(o) {}
              };
              
              ... // further lib class wrappers
              

              Now you can use Base* instead of void* or QVariant.

              SomeLibClassA *a = new SomeLibClassA(...); // somewhere you create your object
              ...
              Base *object = new SomeLibClassAWrapper(a); // you wrap it for your QAbstractItemModel
              ...
              switch(object->type)
              {
              case ClassType::SOME_LIB_CLASS_A:
                  {
                      SomeLibClassA *a = static_cast<SomeLibClassAWrapper*>(object)->object;
                      ... // do your stuff
                  }
                  break;
              case ClassType::SOME_LIB_CLASS_B:
                  {
                      SomeLibClassB *b = static_cast<SomeLibClassBWrapper*>(object)->object;
                      ... // do your stuff
                  }
                  break;
              case ...: // other lib classes
              }
              

              You see that now you can even use static_cast instead of dynamic_cast to avoid some additional runtime overhead.

              You also see that you have to be careful to change a few places when adding another library class you need to use. 1) There's the enum, 2) the wrapper class declaration, and 3) the switch statement (maybe switch statements in multiple places). This makes this solution not elegant in the general case. You have to weigh for yourself if this is a proper solution under the restrictions you have.

              C 1 Reply Last reply
              0
              • S SimonSchroeder

                @crow said in Type Erasure In QModelIndex:

                actually i use dynamic_cast to solve thi problem for now, but there are too many problem with virtual inherit base class, multi inherit and diamond inherit. and i can NOT modify data struct hierarchies because it not write by me. Before use dynamic_cast you also have to change void* to a virtual class pointer but some time the real type is not a virtual class

                One thing that comes to mind is the Curiously Recurring Template Pattern (CRTP). It is not the most elegant solution, but I guess it helps when you cannot change the original classes because they are part of a library.

                Let's assume you have some library classes:

                class SomeLibClassA;
                class SomeLibClassB;
                ... // maybe more classes
                

                The dynamic_cast needs to be replaced with switch over enums later on. So, define your enum:

                enum class ClassType { UNKNOWN, SOME_LIB_CLASS_A, SOME_LIB_CLASS_B, ...}; // add enums for all your classes here
                

                For convenience I suggest a comman base class for all CRTP classes:

                class Base
                {
                public:
                    ClassType type = ClassType::UNKNOWN;
                };
                

                And now for the CRTP template:

                template <class T>
                class CRTPBase : public Base
                {
                public:
                    T *object;
                };
                

                This can now be used to create wrapper classes for the library classes:

                class SomeLibClassAWrapper : public CRTPBase<SomeLibClassA>
                {
                public:
                    SomeLibClassAWrapper(SomeLibClassA *o) : type(ClassType::SOME_LIB_CLASS_A), object(o) {}
                };
                
                class SomeLibClassBWrapper : public CRTPBase<SomeLibClassB>
                {
                public:
                    SomeLibClassBWrapper(SomeLibClassB *o) : type(ClassType::SOME_LIB_CLASS_B), object(o) {}
                };
                
                ... // further lib class wrappers
                

                Now you can use Base* instead of void* or QVariant.

                SomeLibClassA *a = new SomeLibClassA(...); // somewhere you create your object
                ...
                Base *object = new SomeLibClassAWrapper(a); // you wrap it for your QAbstractItemModel
                ...
                switch(object->type)
                {
                case ClassType::SOME_LIB_CLASS_A:
                    {
                        SomeLibClassA *a = static_cast<SomeLibClassAWrapper*>(object)->object;
                        ... // do your stuff
                    }
                    break;
                case ClassType::SOME_LIB_CLASS_B:
                    {
                        SomeLibClassB *b = static_cast<SomeLibClassBWrapper*>(object)->object;
                        ... // do your stuff
                    }
                    break;
                case ...: // other lib classes
                }
                

                You see that now you can even use static_cast instead of dynamic_cast to avoid some additional runtime overhead.

                You also see that you have to be careful to change a few places when adding another library class you need to use. 1) There's the enum, 2) the wrapper class declaration, and 3) the switch statement (maybe switch statements in multiple places). This makes this solution not elegant in the general case. You have to weigh for yourself if this is a proper solution under the restrictions you have.

                C Offline
                C Offline
                crow
                wrote on last edited by
                #11

                @SimonSchroeder said in Type Erasure In QModelIndex:

                Curiously Recurring Template Pattern

                thank for your reply.
                i think this mothod is same to Type Erasure. It work on many scene, but not QModelIndex.
                Let me show you why.

                1. before create a QModelIndex, we warp a class pointer in a new Class
                2. we pass new pointer with type info into QModelIndex as a void*
                3. now we can get right type info
                4. the question is, how to release this NEW WARP Class pointer? When? If we use a QVatiant, wo can pass object not a pointer would release auto when QModelIndex release
                jeremy_kJ 1 Reply Last reply
                0
                • C crow

                  @SimonSchroeder said in Type Erasure In QModelIndex:

                  Curiously Recurring Template Pattern

                  thank for your reply.
                  i think this mothod is same to Type Erasure. It work on many scene, but not QModelIndex.
                  Let me show you why.

                  1. before create a QModelIndex, we warp a class pointer in a new Class
                  2. we pass new pointer with type info into QModelIndex as a void*
                  3. now we can get right type info
                  4. the question is, how to release this NEW WARP Class pointer? When? If we use a QVatiant, wo can pass object not a pointer would release auto when QModelIndex release
                  jeremy_kJ Offline
                  jeremy_kJ Offline
                  jeremy_k
                  wrote on last edited by
                  #12

                  @crow said in Type Erasure In QModelIndex:

                  @SimonSchroeder said in Type Erasure In QModelIndex:

                  Curiously Recurring Template Pattern

                  thank for your reply.
                  i think this mothod is same to Type Erasure. It work on many scene, but not QModelIndex.
                  Let me show you why.
                  ...
                  4. the question is, how to release this NEW WARP Class pointer? When? If we use a QVatiant, wo can pass object not a pointer would release auto when QModelIndex release

                  QModelIndex is an index into a model. It is not the model.

                  Make the CRTP, polymorphic, QVariant, or whatever object a part of the model. This object's lifetime should that of the model or at least the item in the model. It may need to be part of a data structure that parallels the referenced code that can't be changed. This is also an opportunity to solve the parent tracing problem alluded to.

                  Asking a question about code? http://eel.is/iso-c++/testcase/

                  C 1 Reply Last reply
                  1
                  • jeremy_kJ jeremy_k

                    @crow said in Type Erasure In QModelIndex:

                    @SimonSchroeder said in Type Erasure In QModelIndex:

                    Curiously Recurring Template Pattern

                    thank for your reply.
                    i think this mothod is same to Type Erasure. It work on many scene, but not QModelIndex.
                    Let me show you why.
                    ...
                    4. the question is, how to release this NEW WARP Class pointer? When? If we use a QVatiant, wo can pass object not a pointer would release auto when QModelIndex release

                    QModelIndex is an index into a model. It is not the model.

                    Make the CRTP, polymorphic, QVariant, or whatever object a part of the model. This object's lifetime should that of the model or at least the item in the model. It may need to be part of a data structure that parallels the referenced code that can't be changed. This is also an opportunity to solve the parent tracing problem alluded to.

                    C Offline
                    C Offline
                    crow
                    wrote on last edited by
                    #13

                    @jeremy_k said in Type Erasure In QModelIndex:

                    alluded

                    so this "Abstract" model just for static model. Image that you have a dynamic tree with thousands of items. As time goes by, thousands of items add to tree, and thousands of items remove. and the model hold item warp index object which have been romove from tree and never use again because model lifetime is at the end. the memory usage must be crazy.

                    finally, I solve this problem by create a new view/model framework which can handle more hierarchy type. it take time but i need it.
                    just a litte discussion even not a advice for Qt Framework. Whatever, my problem end

                    Thank for your patience

                    jeremy_kJ 1 Reply Last reply
                    1
                    • C crow

                      @jeremy_k said in Type Erasure In QModelIndex:

                      alluded

                      so this "Abstract" model just for static model. Image that you have a dynamic tree with thousands of items. As time goes by, thousands of items add to tree, and thousands of items remove. and the model hold item warp index object which have been romove from tree and never use again because model lifetime is at the end. the memory usage must be crazy.

                      finally, I solve this problem by create a new view/model framework which can handle more hierarchy type. it take time but i need it.
                      just a litte discussion even not a advice for Qt Framework. Whatever, my problem end

                      Thank for your patience

                      jeremy_kJ Offline
                      jeremy_kJ Offline
                      jeremy_k
                      wrote on last edited by
                      #14

                      @crow said in Type Erasure In QModelIndex:

                      @jeremy_k said in Type Erasure In QModelIndex:

                      alluded

                      I don't know what quoting this word on its own means.

                      so this "Abstract" model just for static model. Image that you have a dynamic tree with thousands of items. As time goes by, thousands of items add to tree, and thousands of items remove.

                      This doesn't describe anything that QAbstractItemModel can't be used for. The efficiency of the underlying data structure and access patterns will have an impact on performance, but this is true for data structures in general.

                      and the model hold item warp index object which have been romove from tree and never use again because model lifetime is at the end. the memory usage must be crazy.

                      Why is storing the type for a mixed data tree's node in the tree more expensive that storing them separately? If that data is only stored in a temporary index, how is that index constructed in the first place?

                      Asking a question about code? http://eel.is/iso-c++/testcase/

                      1 Reply Last reply
                      1

                      • Login

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