Function array within a class for a menu

Thanks to everyone on this forum, I normally find my answers without needing to post.
I am creating a menu for an amplifier, I could do it with ‘if’ statements but came across function pointer arrays somewhere… I am using a rotary encoder with a button and have a few menus so this would be an ideal solution. I have tried using a typedef for the array but that would not work either.
I get this error message - cannot convert ‘PreampCore1::settingsMenu’ from type ‘void (PreampCore1::)()’ to type 'void ()()’
void (
[4])(){(), (), (), ()}

void inputSelect(){};
void balanceSet(){};
void settingsMenu(){};
void menu()
    {
        int8_t totalOptions = 5;
        int8_t totalFunctions = 4; // only 4 because we have a BACK as last option
        int8_t menuPos = 1;
        const char *menuOptions[] =
            {// the options in this menu
             "STANDBY",
             "INPUT",
             "BALANCE",
             "SETTINGS",
             "BACK"};

        void (*menuFunctions[])() =
            {// function for each option
             Standby,
             inputSelect,
             balanceSet,
             settingsMenu};  // error squiggly is here
        int8_t i;
        i = uiMenu(totalOptions, menuOptions, menuPos); // returns the users selection
        if (i < totalFunctions)
        {
            (*menuFunctions[i])(); // calls the function
        }
        return; // not needed :)
    }

int8_t uiMenu(int8_t totalOptions, const char *menuOptions[], int8_t menuStartPos)
    { // not coded yet
        int i;
        return i;
    };

I based my code on this example. Declare an array of pointers to functions in Visual C++. It was the simplest example I could find in C++ just noticed it is Visual.

/*
 * Compile options needed: none
 */

#include <stdio.h>

void test1();
void test2();            /*  Prototypes */
void test3();

/* array with three functions */
void (*functptr[])() = { test1, test2, test3 } ;

void main()
{
   (*functptr[0])();    /*  Call first function  */
   (*functptr[1])();    /*  Call second function */
   (*functptr[2])();    /*  Call third function  */
}

void test1()
{
   printf("hello 0\n");
}

void test2()
{
   printf("hello 1\n");
}

void test3()
{
   printf("hello 2\n");
}

Is this a member function in a C++ class? Then it’s not of type void ()(). Member functions need an object instance. Try using std::function instead.

Thanks for the reply. I am not a great coder (you probably noticed) and the simplest things can confuse me. This did not work.

void (*menuFunctions[])() =
            {// functions each option
             PreampCore1::Standby,
             PreampCore1::inputSelect,
             PreampCore1::balanceSet,
             PreampCore1::settingsMenu};

cannot convert ‘PreampCore1::settingsMenu’ from type ‘void (PreampCore1::)()’ to type ‘void (*)()’

I did test the example code outside of a class and it works.

#include <Arduino.h>
 void test1();
  void test2(); /*  Prototypes */
  void test3();
void setup()
{
 
  Serial.begin(115200);
  
  /* array with three functions */
  void (*functptr[])() = {test1, test2, test3};

  (*functptr[0])(); /*  Call first function  */
  (*functptr[1])(); /*  Call second function */
  (*functptr[2])(); /*  Call third function  */
}

void test1()
{
  Serial.println("hello 0\n");
}

void test2()
{
  Serial.println("hello 1\n");
}

void test3()
{
  Serial.println("hello 2\n");
}

// put your setup code here, to run once:


void loop()
{
  delay(100);
  // put your main code here, to run repeatedly:
}

This code works. My array and functions are in a class and are public.

Can you share a minimal version of the project that is non working?

I am giving up for the time being. I have spent too much time on this and will use a few if’s instead of an array. All the functions were member functions. It was so simple outside of a class!

Turn the raw function pointers into std::function<void()> objects and it should work perfectly fine inside a class. Or make the target functions static so that they don’t require an object instance.

OK I will try again. Thank you Max. Here are is the menu using the if’s, it works well but it would be easier with the array.

 void inputSelect(){};
    void balanceSet(){};
    void settingsMenu(){};
    void menu()
    {
        int8_t totalOptions = 5;
        int8_t totalFunctions = 4; // only 4 because we have a BACK as last option
        int8_t menuPos = 1;
        const char *menuOptions[] =
            {// the options in this menu
             "STANDBY",
             "INPUT",
             "BALANCE",
             "SETTINGS",
             "BACK"};

        // void (*menuFunctions[])() = { Standby,inputSelect,balanceSet,settingsMenu};
        int8_t i;
        i = uiMenu(totalOptions, menuOptions, menuPos); // returns the users selection
        if (i < totalFunctions)
        {
            if (i == 0)
                Standby();
            else if (i == 1)
            {
                inputSelect();
                
            }
            else if (i == 2)
                balanceSet();
            else if (i == 3)
                settingsMenu();
        }
        return; // not needed :)
    }

    int8_t uiMenu(int8_t totalOptions, const char *menuOptions[], int8_t menuStartPos)
    {
        int current = menuStartPos; // displays 3 current, next and prev
        int prev, next;

        init = true; // needed to draw first instance of menu
        ofr.setFontSize(80);
        tft.fillScreen(TFT_BLACK);
        if (totalOptions > 2)
        {
            while ((*encoderButton)() != 1) // loop until user makes an option (the rotary encoder and button are not member functions)
            {
                int i = (*encoderMove)(); // returns encoder movement -1 (CCW), 0 (NO MOVE) or 1 (CW)
                if (i != 0 || init==true)
                {
                    init = false;
                    current += i;
                    Serial.println(current);
                    // keep current in range
                    if (current < 0)
                        current = totalOptions - 1;
                    if (current >= totalOptions)
                        current = 0;
                    // set next and prev
                    if (current == 0)
                    {
                        prev = totalOptions - 1;
                        next = current + 1;
                    }
                    else if (current == totalOptions - 1)
                    {
                        prev = current - 1;
                        next = 0;
                    }
                    else
                    {
                        prev = current - 1;
                        next = current + 1;
                    }
                    // draw options to screen, current is white and in middle, next and prev are lightgrey
                    tft.fillRect(0, 20, 480, 80, TFT_BLACK);
                    ofr.cdrawString(menuOptions[prev], 239, 0, TFT_DARKGREY, VDARKGREY);
                    tft.fillRect(0, 120, 480, 80, TFT_BLACK);
                    ofr.cdrawString(menuOptions[current], 239, 100, TFT_WHITE, TFT_BLUE);
                    tft.fillRect(0, 220, 480, 80, TFT_BLACK);
                    ofr.cdrawString(menuOptions[next], 239, 200, TFT_DARKGREY, VDARKGREY);
                }
            }
        }
        if (totalOptions == 2) // to be written
        {
            delay(1);
        }
        if (totalOptions == 1) // to be written, this will be a slider. needs more thought
        {
            delay(1);
        }
        tft.fillScreen(TFT_BLACK);
        init = true;
        return current;
    }