Search code examples
c++templatestreeunique-ptrtype-safety

C++ tree/forest structure for nodes of different class types


\\while implementing a solution found with casting over a a common baseclass

\\ with virtal members.

\\i found out about univeral references, because that is a other question i created a new one:

https://stackoverflow.com/questions/29590429/c-is-it-possible-to-use-universal-references-for-a-tree-forest-with-nodes-that

please refer also to this original question.

I want to organize the hierarchical tree structure of objects with different types.

The solution should do its work at compile time, so i found out that i have to do this with templates at best without any casting.

after some try's that are in the editlog and had some fundamental flaws.

i found a way to split it up in two classes

  • forest that stores all the nodes and does give them two coordinates the indexnumbers in the vector< vector <...> >

  • node a template < T > that stores the T Object and the relationship to the other nodes

my idea does not yet have a way to access the memberfunctions of the Objects stored inside the node class, without breaking the unique_pointer that secures the resourcemanagement.

and i would like to know how to ensure typesafty when accessing a object inside the node class.

there may be errors inside the code, i'm quite sure that it will not compile, the question is about the concept.

Questions are inside the comments.

verion 4:

 class Forest
 {
  public:
     template<typename T>
     {friend class Node<T>;} \\every Node<T> should have access to the forest
     Forest();
     ~Forest();
     Forest(const Forest&)=delete;  \\does not make any sense to copy or assign the forest to another forest.
     Forest operator=(const Forest&)=delete;
     int insertroot()  \\every tree has a void nullptr seed/root so that the forest does not need to be templatet, returns the treenumber
     {    \\implementation
     if(this->Nodes.size()==0)
        {
           std::vector<std::unique_ptr<Node<void> > > h0;
           h0.push_back(std::unique_ptr<Node<void>(new Node<void>(nullptr));
           this->Nodes.push_back(h0);
        }else
        {
             this->Nodes[0].push_back(std::unique_ptr<Node<void>(new Node<void>(nullptr,this)));
        }
     return this->Nodes[0].size()-1;

     }
     Node<void>* getroot(int i)   \\ to later allow access to the children and the Objects inside them
  {
     if(Nodes.size>0){
      if((i>0)&(i<Nodes[0].size()))
      {
          return Nodes[0][i].get();
      }
  }
  private:
      std::vector<std::vector<unique_ptr<Node<void> > > nodes; \\is it possible to fill this vector with any Node<T>? its a vector*2 to a unique_ptr to a classpointer with a member pointer to any class. from what i read about templates they create a extra class  for every type, so basicly the unique_ptr have a different type and i cannot store different types in a vector without casting?
 }

 template<typename T>
 class Node
 {
   public:
      Node(T n,Forest * Fo) \\ every Node is in the forest and has access to the other nodes and forest information
      :object(std::unique_ptr(n)),F(Fo)
      {
          if(n==nullptr)
          {    
               this->lvl=0;
               this->place=F->Node[0].size();
               this->parent=-1;
          }
      }
      ~Node();
      Node(const Node&)=delete;
      Node operator=(const Node&)=delete;
      T getObject(){return object.get();} \\how does the compiler know the type? see getchild 

      template<typename C>
      {
         Node<C> * getchild(int){}   \\not yet exsisting implementation of get child[int] how do i teach the compiler what int responds to what type?
                                     \\when i understand templates correct then Node<C> are different Classes for every C??
        addChild(C c)
        {
           Node * n=new Node(c,this->F);
           n->parent=this->place;
           n->lvl=this->lvl+1
           if(F->nodes.size()<=n->lvl)
           {
              n->place=0;
              h0=std::vector<unique_ptr<Node<C>> >;  
              h0.push_back(unique_ptr<Node<C>(n))
              F->Nodes.push_back(h0); \\are vector<uniptrNode<C> > and vector<uniptrNode<void>> compatible?
           }else
           {
              n->place=F->nodes[n->lvl].size();
              F->Nodes[n->lvl].push_back(unique_ptr<Node<C> >(n));
           }
           this->children.push_back(c->place);
        } 
      }        
   private:
     int parent,place,lvl;
     std::vector<int> children;
     unique_ptr<T> object;
     Forest * F;
 }

does anyone know a way to implement a container like this? maybe there is some abstract type type i did not find out about, so do that i can add a method type getnodetype(int) or checknodetype(int,type), could i assign this with auto nodex=y->getObject()? But then how does the compiler know what methodes nodex has and does not has?

EDIT: i removed the original Post because v4 is very close to a working solution version 1-3 should be in the editlog


Solution

  • I think you need something like boost.any or QVariant.