Home > Software engineering >  How to iterate over a template class?
How to iterate over a template class?

Time:10-31

I'm trying to create a generic menu class that will be used with a 4 line LCD.

I have a specific (non template) version working, but want to extend it to allow the menu to modify a variety of data types (int, float, unsigned...).

Here's the non template version that's working as expected...

/*
 * ideally this design allows for defining an arbitrary menu as shown below
 * example...
 * root1
 *    sub1-1
 *    sub1-2
 * root 2
 * root 3
 *   sub3-1
 *   sub3-2
 *     sub3-2-1
 *     sub3-2-2
 *     
 * each node in the menu can be executed, and allow for moving to the next/prev sibling or child/parent
 * this flexibility requires that each node contains pointers to parent, child, and sibling nodes.
 */


class  MenuNode
{
  private:
  char *prompt;
  int value;
  public:
  MenuNode *parent=NULL;
  MenuNode *child=NULL;
  MenuNode *prevSibling=NULL;
  MenuNode *nextSibling=NULL;
  void SetValue(int value)
  {
    this->value = value;
  }
  int GetValue()
  {
    return value;
  }
  char *Prompt()
  {
    return prompt;
  }
  MenuNode(char *prompt, int initialValue, MenuNode *parent, MenuNode *prevSibling)
  {
    Serial.print(prompt);Serial.println(F(" MenuNode"));
    this->prompt = prompt;
    if (prevSibling != NULL)
    {
      this->prevSibling = prevSibling;
      prevSibling->SetNextSibling(this);
      this->parent = prevSibling->parent;
    }
    // prevSibling if provided sets the parent
    if (prevSibling==NULL && parent != NULL) 
    {
      this->parent = parent;
      this->parent->SetChild(this);
    }
    
    value = initialValue;
  }
  void SetChild(MenuNode *child)
  {
    Serial.print(prompt);Serial.println(F(" SetChild"));
    this->child = child;
  }
  void SetNextSibling(MenuNode *nextSibling)
  {
    Serial.print(prompt);Serial.println(F(" SetNextSibling"));
    this->nextSibling = nextSibling;
  }
};

Here's some test code that creates the menu structure...

// Test menu... 
MenuNode r1("R1",10,NULL,NULL);
MenuNode r2("R2",20,NULL,&r1);
  MenuNode r21("R21",30,&r2,NULL);
  MenuNode r22("R22",40,&r2,&r21); // setting parent is optional, the parent will be set by the prev sibling parent
    MenuNode r221("R221",50,&r22,NULL);
      MenuNode r2211("R2211",60,&r221,NULL);
      MenuNode r2212("R2212",70,NULL,&r2211);
MenuNode r3("R3",30,NULL,&r2);

This code iterates over each element printing out the structure

void PrintMenuStructure(MenuNode *node,int offset)
{
  while(node != NULL)
  {
    for (int i=0;i<offset;i  )
      Serial.print("-");
    Serial.print(node->Prompt());
    Serial.print(" = ");
    Serial.print(node->Value());
    if (node->parent != NULL)
    {
      Serial.print(" parent=");
      Serial.print(node->parent->Prompt());
    }
    if (node->prevSibling != NULL)
    {
      Serial.print(" prevSib=");
      Serial.print(node->prevSibling->Prompt());
    }
    if (node->nextSibling != NULL)
    {
      Serial.print(" nextSib=");
      Serial.print(node->nextSibling->Prompt());
    }
    if (node->child != NULL)
    {
      Serial.print(" child=");
      Serial.print(node->child->Prompt());
    }
    Serial.println();
    if (node->child != NULL)
      PrintMenuStructure(node->child,  offset);
    node = node->nextSibling;
  }
}

This is the output of the previous function demonstrating the structure of the menu...

R1 = 10 nextSib=R2
R2 = 20 prevSib=R1 nextSib=R3 child=R21
-R21 = 30 parent=R2 nextSib=R22
-R22 = 40 parent=R2 prevSib=R21 child=R221
--R221 = 50 parent=R22 child=R2211
---R2211 = 60 parent=R221 nextSib=R2212
---R2212 = 70 parent=R221 prevSib=R2211
-R3 = 30 prevSib=R2

It all works the way I want, but GetValue/SetValue only operate on int data.

I can create a template version of the class, with the data types of GetValue and SetValue defined by the template parameter, but I don't know now to iterate over the nodes once I do that.

Seems like a simple enough task, but I've been beating my head against the wall for a while, and haven't come up with anything that works. Any help pointing me in the right direction would be appreciated.

I'm trying to figure out how to iterate over a linked list of classes, but can't figure out how to get a pointer to start iterating.

Sorry, I couldn't get the code formatting to work... :(

CodePudding user response:

The way I interpret your requirement: it seems your should make your

int value;

a std::variant.

That's the lowest cost path.

If you templatize the MenuNode class with its value type. Then a MenuNode<int>* cannot be the parent of a MenuNode<float*>, etc. Not without some effort. You'd probably better off make it polymorphic by derivate each type of value your want to support from a common abstract virtual base, and depend on how you want to use the value, design your interface.

  • Related