Структура дерева/леса С++ для узлов разных типов классов

\\ при реализации решения, найденного с помощью приведения к общему базовому классу

\\ с виртуальными членами.

\\ я узнал об универсальных ссылках, потому что это другой вопрос, я создал новый:

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

пожалуйста, обратитесь также к этому исходному вопросу.

Я хочу организовать иерархическую древовидную структуру объектов разных типов.

Решение должно выполнять свою работу во время компиляции, поэтому я обнаружил, что мне нужно делать это в лучшем случае с шаблонами без какого-либо приведения.

после некоторых попыток, которые находятся в журнале редактирования и имели некоторые фундаментальные недостатки.

я нашел способ разделить его на два класса

  • лес, который хранит все узлы и дает им две координаты indexnumbers в векторе‹ вектор ‹...> >

  • node шаблон ‹ T >, в котором хранится объект T и связь с другими узлами

в моей идее еще нет способа получить доступ к функциям-членам объектов, хранящихся внутри класса узла, без нарушения уникального указателя, который обеспечивает управление ресурсами.

и я хотел бы знать, как обеспечить безопасность типов при доступе к объекту внутри класса узла.

внутри кода могут быть ошибки, я совершенно уверен, что он не скомпилируется, вопрос в концепции.

Вопросы внутри комментариев.

версия 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;
 }

кто-нибудь знает способ реализовать такой контейнер? может быть, есть какой-то абстрактный тип, о котором я не знал, поэтому я могу добавить тип метода getnodetype (int) или checknodetype (int, type), могу ли я назначить это с помощью auto nodex = y-> getObject ()? Но тогда как компилятор узнает, какие методы есть у nodex, а какие нет?

РЕДАКТИРОВАТЬ: я удалил исходный пост, потому что v4 очень близок к рабочему решению, версия 1-3 должна быть в журнале редактирования.


person Philipp    schedule 12.04.2015    source источник
comment
Ваш деструктор не нужен. Контейнеры и интеллектуальные указатели существуют, поэтому вам не нужно вручную удалять данные.   -  person Neil Kirk    schedule 12.04.2015
comment
деструктор существует, так что дети сначала удаляются перед объектом   -  person Philipp    schedule 12.04.2015
comment
Почему это имеет значение? В любом случае дочерние элементы будут удалены перед объектом, поскольку он появляется после него в определении класса. Если ваш класс требует, чтобы что-то удалялось в определенном порядке, вы должны задокументировать это в комментарии.   -  person Neil Kirk    schedule 12.04.2015
comment
Почему бы вам не использовать template<class T, class T2, class T3> …? Или использовать T1 вместо обычного T?   -  person Jonathan Leffler    schedule 12.04.2015
comment
потому что я не очень разбираюсь в шаблонах, и я не знал, должны ли шаблоны быть дополнительными шаблонами для общедоступных функций-членов. таким образом, если t1 является одним и тем же void или base, компилятор генерирует один класс с разными перегрузками для функции addchild?   -  person Philipp    schedule 12.04.2015
comment
@NeilKirk, я не уверен, что это будет иметь значение в моей конкретной проблеме, объекты являются специальными QWidgets, и мне, возможно, придется обработать удаление встроенных QWidgets до QWidgets, в которые они встроены.   -  person Philipp    schedule 12.04.2015
comment
Вектор может хранить данные только одного типа. Таким образом, вы не можете помещать в вектор объекты типа Node‹MyNode1› и Node‹MyNode2› одновременно, потому что они разного типа.   -  person gomons    schedule 12.04.2015
comment
Я думаю, вам нужно что-то вроде boost.any или QVariant. Но мое предложение, чтобы хранить узлы разных типов в одном контейнере, им нужен общий родитель с виртуальным методом doStuff(). Когда вы проходите по дереву, просто вызовите doStuff() в базовом классе. Вы можете посмотреть шаблон посетителя.   -  person gomons    schedule 12.04.2015


Ответы (1)


Я думаю, вам нужно что-то вроде boost.any или QVariant.

person gomons    schedule 12.04.2015
comment
Или std::experimental::any<>, выделенный из C++14 в отдельную TS, поддерживаемую некоторыми компиляторами. - person набиячлэвэли; 12.04.2015