Function templates and void pointers

I have a menu class which contains a void pointer. Each menu object has a void pointer called value pointing to another variable, this variable could be a int, float, double anything. I could store the type of the void pointer inside the class as well but I don't know how to store a type like an int etc inside a variable, typename type = int; doesn't work obviously;

I'm trying to set my RTC time to a value pointed at by a void pointer. To do this I am trying to write a template function that will return the value pointed at by the void pointer.

I need to know how to store a typename (like int etc), so that I can compare inside a switch statement and return the right value. This is what I have so far inside the menu class:

void *value;

    template <typename Type> 
    Type Value(Type type)
    {
      //void *ptr;
    
      switch (Type)
      {
      case int:
     //ptr= *static_cast<int*>(*value);
     return static_cast<int>(*value);
     break;
     return *ptr;
      }
    }

But the switch(Type) gives the following error:

"menu11.ino:180:62: note: candidate expects 1 argument, 0 provided
expected primary-expression before ')' token"

Maybe I need to create a separate pointer type for each case and cast the original pointer to it but for now I need to know what typename is being passed to the function. As far as I know there is no way to get the type of a variable or to store a type like an int inside a variable.

The code I am trying to write is an amalgamation of these two ideas:

References: http://www.learncpp.com/cpp-tutorial/613-void-pointers/
http://www.learncpp.com/cpp-tutorial/141-function-templates/

 void *value;
   :
 return static_cast<int>(*value);

This is a bit beyond by C++ knowledge, but surely you need to cast "value" to something other than "void*" before you can dereference it with "*" ? Maybe:

     return *( static_cast<int *>(value));

Well according to http://www.learncpp.com/cpp-tutorial/613-void-pointers/ a void pointer must be cast to another pointer type before being dereferenced:

int value = 5;
void *voidPtr = &value;
 
//cout << *voidPtr << endl; // illegal: cannot dereference a void pointer
 
int *intPtr = static_cast<int*>(voidPtr); // however, if we cast our void pointer to an int pointer...
 
cout << *intPtr << endl; // then we can dereference it like normal

However my function must be able to return any type, hence my attempt at incorporating the void pointer into function templates, if this works:

template <typename Type> // this is the template parameter declaration
Type max(Type tX, Type tY)
{
    return (tX > tY) ? tX : tY;
}

Then I just need a way to check what typename Type is, then I can cast and return as required.

HOWEVER, first I must be able to determine what Type is.

Thank you, that looks like a very informative page. Could you help apply it to my situation?

I am using template functions to handle the type, so that it can return any type. I need to check what the type is that is being passed into the template function, so that I can handle the void pointer and thus return types accordingly.

Basically, a class object holds a void pointer to potentially any value type. Given that I know which type to call for, I need a function which takes the void pointer, and casts it to a pointer of required type, and then dereferences it. But to know which type or "typename" to cast the void pointer to requires knowing what the required type is.

So my code is stuck at the switch (Type) statement, because I do not know how to check what type the argument being passed into the template function is.

i.e.

    template <typename Type> //template parameter declaration 
    Type Value(Type type) // return type Type, argument type, type
    {
    
      switch (typeof(type)) // WHAT TYPE IS Type? This is where the code error is
      {
      case int:  // If I knew what type it was 
     //int* ptr= *static_cast<int*>(*value); // Then I could create a temporary pointer of appropriate type

     return *( static_cast<int *>(value)); // wesfw's suggestion
     //return static_cast<int>(*value);
     break;
     return *ptr; //or return the result of dereferencing ptr 
      }

Yes that is what I am trying to do essentially. But if I don't use a void pointer what will I use to store an arbitrary number? I would end up writing a separate class for each data type and it would defeat the purpose.

The template function allows me to exchange unknown types for types known at run time I believe. Either way I do it, I still need to know how I can compare an existing type (int double etc) to an argument passed into the function template?

I just don't know how to solve this problem without void pointers, how can I access a variable inside a class object that could be any data type? How do I represent said variable without creating separate variables for each type?

My solution was to point to an existing variable using a void pointer, it makes it easier that it exists and can be modified outside the class as well. I just need to know what type to cast the void pointer to (as an argument to the template function) and then the template function can return any type necessary?

I don't quite understand how you intend to use this. Can you give us an example of how you're filling in value in the first place, and how you want to access it?

It looks like it might be a job for "union" (which is frequently used to access an area of memory as several different basic types.) (OTOH, I don't know whether this is one of the things for which C++ is supposed to have a "better" way.)

syphex7:
I would end up writing a separate class for each data type and it would defeat the purpose.

No, you would not.

Enough of this mumbo-jumbo. Give a concrete example.

Menu class:

class menu
{
  public:
    int type;
//    typename type;
    char name[10];
    byte color;
    byte xpos;// position on the screen
    byte ypos;
    //byte index[2]; //position in the current menu index
    menu*** menulist; //indexed array pointer to group members
    menu* previous_menu; //pointer to previous menu
    void *value;
    void (*function) ();

    template <typename Type> 
    Type Value(Type)
    {
      //void *ptr;

      Type* ptr=static_cast<Type*>(value);
      return *ptr;
//      switch (typeof(type))
//      {
//      case int:
//     Type* ptr= *static_cast<int*>(*value);
//     return *( static_cast<int *>(value));
//     //return static_cast<int>(*value);
//     break;
//     return *ptr;
//      }
    }


    menu(char *myname = "", byte y = 0, byte x = 0, int c_type = 0, byte m_color = 0)
    {
      strcpy(name, myname);
      color = m_color;
      type = c_type;
      menulist = 0;
      previous_menu = 0;
      value = 0;
      function = 0;

      if (y > 0)
      {
        menulist = new menu**[y + 1];
        menulist[y] = 0;
        for (byte i = 0; i < y; i++)
        {
          menulist[i] = new menu*[x + 1];
          for (byte p = 0; p <= x; p++)
            menulist[i][p] = 0;
        }
      }
    }

    ~menu() {
      for (int i = 0; menulist[i] != 0; ++i) {
        delete [] menulist[i];
      }
      delete [] menulist;

    }


};

Time menu instantiation:

  int second_set = 9; //second();
  int minute_set = 9; //minute();
  int hour_set = 9;//hour();
  int day_set = 9;//day();
  int month_set = 9;//month();
  int year_set = 99;//year();

menu SET_TIME("Time/Date", 2, 4, 0), set_second(":"), set_minute(":"), set_hour("Time:", 0, 0, 0), set_year("/"), set_month("/"), set_day("DATE: ");

void setup()
{
  set_hour.value = &hour_set;
  set_minute.value = &minute_set;
  set_second.value = &second_set;
  set_day.value = &day_set;
  set_month.value = &month_set;
  set_year.value = &year_set;


  SET_TIME.menulist[0][0] = &OPTIONS;
  SET_TIME.previous_menu = &OPTIONS;
  SET_TIME.menulist[0][1] = &set_hour;
  SET_TIME.menulist[0][2] = &set_minute;
  SET_TIME.menulist[0][3] = &set_second;
  SET_TIME.menulist[1][0] = &set_day;
  SET_TIME.menulist[1][1] = &set_month;
  SET_TIME.menulist[1][2] = &set_year;
  SET_TIME.function=SetRTCTime;
}

When select is pressed call the current menu's function

void loop() {
 if (buttons & BUTTON_SELECT) {
        Serial.println("select pressed");
        
        if (current_menu->function!=0) 
        {
          Serial.println("Calling "+(String)current_menu->name +"'s function");// Serial.print(current_menu->name);
          (*(current_menu->function))();
        }
        else Serial.println("no function detected");
}

SET_TIME's function pointer is set to this function:

void SetRTCTime()
{
  Serial.println("calling setrtc function");
  setTime(hour_set,minute_set,second_set,day_set,month_set,year_set);
  RTC.set(now());
     setSyncProvider(RTC.get);   // the function to get the time from the RTC
   if(timeStatus()!= timeSet)
      Serial.println("Unable to sync with the RTC");
   else
      Serial.println("RTC has set the system time to "+(String)hour_set+":"+(String)minute_set+":"+(String)second_set);
}

Here is a function to change the value a menu object is pointing at:

void change_value(void *ivalue, int type, int sign)
{
  int exponent = int(2 * (float(holdtimer) / 20.0));
  switch (type)
  {
    case 0:
      {

        int* nvalue = static_cast<int*>(ivalue);
        *nvalue += (int)sign * pow(10, exponent);
        //Serial.print("Exponent value: "); Serial.println(pow(10,exponent));
        break;
      }
    default:
      {
        double* pvalue = static_cast<double*>(ivalue);
        if (type == 1)
          *pvalue += (double)0.1 * sign * pow(10, exponent);

        if (type == 2)
          *pvalue += (double)0.01 * sign * pow(10, exponent);
        break;
      }
  }
}

But it requires me to use ints or an enum to store the type, I would rather just store the type int itself in each menu object. Then I can use that as an argument to get the type that needs to be returned by the template function Value() inside the menu class I am trying to write. The only way I can think of "storing" the type like int is to use a pointer to the int class itself, but this obviously needs to be a void pointer. If there is another way please give me an example instead.

Well, I don't think a template would work, since it's a compile-time abstraction, whereas it looks like you want to derive the type from the selected menu item at runtime, right? I don't think you can actually do much better than the code you have now (small integers/enums with assigned meanings.)

        *nvalue += (int)sign * pow(10, exponent);

Using pow() in this sort of operation is ... not necessary, and not a good idea (at least add rouding!)

I ... would do things a lot differently, perhaps with the menus containing pointers to more generic functions (change_int, change_float) AND the value location AND perhaps a display handler.

Can you post your whole code?

http://snippets-r-us.com/

I don't see where you are calling "change_value".

Sorry my code exceeds the 9000 character limit. Come to think of it change_value should be called increment/decrement_value, since its not an assignment function at all. Maybe I should write one, but I would rather overload an assignment operator somehow.

Here is my display handler for whoever asked:

void display_menu()
{
  char buffer[5];
  byte xpos = 1;
  for (int i = index_offset - 1; i <= index_offset; i++)
  {

    //display_selection();
    xpos = 1;
    for (int p = 0; (current_menu->menulist[i][p]) != 0; p++)
    {

      current_index_menu = current_menu->menulist[i][p];
      //Serial.println(p);
      //Serial.print(" ");
      // delay(1000);
      //lcd.setCursor(xpos);
      lcd.setCursor(xpos, 1 - (index_offset - i));
      //if (current_index_menu!=current_menu)
      if (current_index_menu == current_menu->previous_menu)
      {
        lcd.setCursor(0, 0);
        lcd.write((uint8_t)0);
        if (current_index[Y] == i && current_index[X] == p)
        {
          lcd.setCursor(0, 1);
          lcd.print("^");
        }
        //xpos+=1;
      }
      else      //print the
      {
        lcd.setCursor(xpos, 1 - (index_offset - i));
        if ((current_index_menu->menulist != 0) && (current_index[Y] == i && current_index[X] == p)) //if the current menu has other items and the current i and p values correspond to the current index
        {
          if (current_menu != &MAIN)
          {
            lcd.setCursor(xpos - 1, 1 - (index_offset - i));
            lcd.print(">");
          }
          lcd.print(current_index_menu->name);
          xpos += strlen(current_index_menu->name);
          if (current_index_menu->value != 0) /////////////////////
          {

            lcd.setCursor(xpos - 1, 1 - (index_offset - i));
          }
          if (current_menu != &MAIN)
            lcd.print("<");
        }
        else
        {
          lcd.print(current_index_menu->name);
          xpos += strlen(current_index_menu->name);
        }


        if (current_index_menu->value != 0)
        {

          if ((current_index[Y] == i && current_index[X] == p) && (current_index_menu->menulist == 0))
          {
            if (main_selected == 0)
            {
              lcd.setCursor(xpos - 1, 1 - (index_offset - i));
              if (menu_selected)
                lcd.print("<");
              else
                lcd.print(">");
            }
          }
          lcd.setCursor(xpos, 1 - (index_offset - i));

          switch (current_index_menu->type) {
            case 0:
              {
                int* pvalue = static_cast<int*>(current_index_menu->value);
                printDigits(*pvalue); //print the value to the lcd
              }
              break;
            default:
              lcd.print (*(double*)(current_index_menu->value), current_index_menu->type);
              break;
          }


          //xpos+=4;
          //xpos+=strlen(dtostrf(*(double*) current_index_menu->value,3,current_index_menu->type,buffer));
          if (current_menu == &SET_TIME) xpos += 2;
          else
            xpos += 4;
          //xpos+=strlen(dtostrf(*(double*) current_index_menu->value,3,current_index_menu->type,buffer));

          if ((current_index[Y] == i && current_index[X] == p) && (current_index_menu->menulist == 0))
            if (main_selected == 0)
            {
              if (menu_selected)
                lcd.print(">");
              else
                lcd.print("<");
              //xpos+=1;
            }

        }

        if (current_menu != &SET_TIME) xpos++;
      }
      //Serial.println();
    }
  }

}

I think I'll just assign my value pointer in the menu class to an allocated variable inside the menu class's constructor.

Example:

    class menu (arguments)
{
//other stuff

void* value; // void pointer called value

    menu() //constructor
{ 
      enum TYPE {INT, FLOAT, DOUBLE};

      switch (type)
      {
        case INT:
        value = new int;
        break;
        case FLOAT:
        value = new float;
        break;
        case DOUBLE: 
        value = new double;
        break;
      }
}
}

But now it seems I need to override the assignment operator so that I can assign the value of the allocated variable to an existing variable's value. This brings me to the question of how to override the assignment operator for the value void pointer only, and not the menu class itself. So that when I do something like menu1.value = *variable, it will know what to cast *variable to, and also only override the assignment operator for the void pointer value.

How do I override the assignment operator for a variable (or pointer) inside a class?

syphex7:
This brings me to the question of how to override the assignment operator for the value void pointer only, and not the menu class itself. So that when I do something like menu1.value = *variable, it will know what to cast *variable to, and also only override the assignment operator for the void pointer value.

Sorry, is your intention to dereference a pointer to an int, float or double and assign to a single class data member?

BulldogLowell:
Sorry, is your intention to dereference a pointer to an int, float or double and assign to a single class data member?

Well the void pointer called value IS a member of the menu class. But because its a void pointer, another pointer of the correct type must be cast to change the value that its POINTING to, e.g.

int storedvalue=3;
void *value = &storedvalue;
 int* nvalue = static_cast<int*>(value);
        *nvalue = (int)5; //change storedvalue to 5

That will change storedvalue to 5.

So now my intention is to override the assignment operator for the menu class so that it will create a pointer of the appropriate type, assign the value pointer inside the menu class to it, and then indirectly set value to it using the trick above.

I have now set the void pointer called value to an allocated variable in the menu class constructor using the new keyword, so when I call the assignment operator on menu, hopefully it changes the value of the variable pointed to by the void pointer. Why didn't I just create a variable of every necessary type inside the menu class? Because I don't want to waste memory by initializing a variable of every type when I just want to represent e.g the hour the RTC is set to in a menu.

All this is just so that I can change any variable of any type from my menu system, and also store and retrieve any type of variable from a menu object.

How do you plan on reading the value.

You are going to need to have a set of if's or a switch to decide what type to retrieve the value as - even if you stored every variable type in the class you'd still need to decide which one to use and how you want to use it.

But to overload the assignment operator for multiple pointer types, you could do something like this:

struct MenuItem{

  void *ptr;

  template< typename T >
    MenuItem &operator =( T *t ){
      
      ptr = new T( *t );
      return *this;
    }
};


void setup() {
  MenuItem m;
  
  float f = 3.14f;

  m = &f;    //Assign pointer to f
}

void loop() {}

However overloading without templates would allow you to record the type easier.

Yes that's exactly the type of thing I am looking for, but don't know how to apply it to my situation. But I am confused, why is the overloaded assignment operator returning a void pointers value? It should be assigning the void pointers value to the value of the parameter.

At the moment I am just using enum Type{INT, FLOAT, DOUBLE}; and using that to store the type in the menu object.

So for example I want to set the time on my RTC using

setTime(hour,minute,second,day,month,year);

But the value I want to use for hour is stored inside a menu object that could be any type, and I need an int.

So if set_hour is a menu object I want to do this:

int hour = *(set_hour.value); //but value can point to any type, and I don't like having to dereference all that. Assume value is already pointing to an int.

setTime(hour,minute,second,day,month,year);

So that it knows set_hour.value is storing (or pointing to) an int. Basically need to retrieve the value pointed to by a void pointer inside set_hour, and cast to the right type to boot. But that's just retrieving the value pointed at by void* value and a completely separate problem to overloading the assignment operator :frowning:

If you know what type to expect, you can use a template conversion operator. I have added a single function (the operator) to my example I posted above.

Note: you do not need a conversion operator, you could use a template function named 'get' for instance.

I have also changed the assignment operator to accept a reference to the value, rather than a pointer.

struct MenuItem{

  void *ptr;

  template< typename T >
    MenuItem &operator =( const T &t ){
      ptr = new T( t );
      return *this;
    }

  template<typename T>
    operator T() const{
      return *(T*)ptr;
    }
};


void setup() {
  MenuItem m;
  
  float f = 3.14f;
  
  m = f;   //Assign the value of f to m

  float val = m;  //retrieve the value stored in m as a float.
}

void loop() {}

Yes that looks like what I need, but I thought I need to override the copy constructor to retrieve the value from it. References: http://www.learncpp.com/cpp-tutorial/911-the-copy-constructor-and-overloading-the-assignment-operator/

  template<typename T>
    operator T() const{
      return *(T*)ptr;
    }

What does this do? Is this the same as overriding the copy constructor?

syphex7:
Yes that looks like what I need, but I thought I need to override the copy constructor to retrieve the value from it.

What does this do? Is this the same as overriding the copy constructor?

No, the copy constructor is used to initialize an object, which would do what the assignment operator does at declaration point.

It would allow you to do:

MenuItem m = 3.14f;

Rather than an assignment (after initialization):

MenuItem m;
m = 3.14f;

However this would really be a 'specific constructor' as opposed to a copy constructor (typically used to copy an object of the same type)


The code you are asking about is a conversion operator. It is allowing the object to be converted implicitly to another type. The function can be marked 'explicit' which will force you to use a cast.

syphex7:
Sorry my code exceeds the 9000 character limit.

You can attach code to a post.

How to use this forum