Массив функций

Я новичок в C++. Как сделать меню без if() {} else {} & случай переключения()? Я сделал меню на массиве, но оно почему-то не компилируется. Как исправить?

typedef void (*cbd)(uint8_t, uint8_t);
typedef void (*cbt)(uint8_t, uint8_t);
typedef void (*cba)(uint8_t, uint8_t);
typedef void (*MenuFunction) (int8_t);

class Menu {
public:
    Menu() {
        updownFns[5] = {updownNone, updownAlarmHours, updownAlarmMinutes, updownTimeHours, updownTimeMinutes};
    }

    static void Setup(cbd display, cbt setTime, cba setAlarm, uint8_t alarmHours, uint8_t alarmMinutes) {
        cbDisplay = display;
        cbSetTime = setTime;
        cbSetAlarms = setAlarm;
        alarmHours = alarmHours;
        alarmMinutes = alarmMinutes;
        cbSetAlarms(alarmHours, alarmMinutes);
    }
    // Используется для обратного вызова menu.UpDown(dir)
    static void UpDown(int8_t direction) {
        updownFn(direction);
    }
    // Используется для обратного вызова menu.Tab()
    static void Tab() {
        updownFnNum++;
        updownFn = updownFns[updownFnNum % 5];
    }

private:

    static void updownNone(int8_t direction) { }

    static void updownAlarmHours(int8_t direction) {
        alarmHours += direction;
        cbDisplay(alarmHours, alarmMinutes);
        cbSetAlarms(alarmHours, alarmMinutes);
    }

    static void updownAlarmMinutes(int8_t direction) {
        alarmMinutes += direction;
        cbDisplay(alarmHours, alarmMinutes);
        cbSetAlarms(alarmHours, alarmMinutes);
    }

    static void updownTimeHours(int8_t direction) {
        timeHours += direction;
        cbSetTime(timeHours, timeMinutes);
        cbDisplay(timeHours, timeMinutes);
    }

    static void updownTimeMinutes(int8_t direction) {
        timeMinutes += direction;
        cbSetTime(timeHours, timeMinutes);
        cbDisplay(timeHours, timeMinutes);
    }

    static uint8_t alarmHours, alarmMinutes, timeHours, timeMinutes;
    static uint8_t updownFnNum; // 0-Нет, 1-ТревогаH, 2-ТревогаM, 3-ВремяH, 4-ВремяM
    static cbd cbDisplay;
    static cbt cbSetTime;
    static cba cbSetAlarms;
    static MenuFunction updownFns[5];
    static MenuFunction updownFn;
};

uint8_t Menu::alarmHours = 0;
uint8_t Menu::alarmMinutes = 0;
uint8_t Menu::timeHours = 0;
uint8_t Menu::timeMinutes = 0;
uint8_t Menu::updownFnNum = 0;
cbd Menu::cbDisplay = NULL;
cbt Menu::cbSetTime = NULL;
cba Menu::cbSetAlarms = NULL;
MenuFunction Menu::updownFn = NULL;

Вывод:

In file included from app.ino:7:0:
menu.h: In constructor 'Menu::Menu()':
menu.h:9:109: error: cannot convert '<brace-enclosed initializer list>' to 'MenuFunction {aka void (*)(signed char)}' in assignment
updownFns[5] = {updownNone, updownAlarmHours, updownAlarmMinutes, updownTimeHours, updownTimeMinutes};

Спасибо!

, 👍1


2 ответа


Лучший ответ:

2

В языке C++ проводится различие между инициализацией и назначение. Инициализация — это начальное значение, которое вы даете переменная в том месте, где вы ее определяете. Задание – это использование оператора = где-либо еще. Кроме того, язык не позволяет присвоение содержимого массива в целом. Вы можете инициализировать хотя массив.

Это:

Menu() {
    updownFns[5] = {updownNone, updownAlarmHours, updownAlarmMinutes,
        updownTimeHours, updownTimeMinutes};
}

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

MenuFunction Menu::updownFns[5] = {updownNone, updownAlarmHours,
    updownAlarmMinutes, updownTimeHours, updownTimeMinutes};
,

0

Во-первых, ваш updownFns[5] может содержать 5 переменных. И индекс последней переменной может быть 4, а не 5, потому что индекс массива начинается с 0.

Вот код:

typedef void (*cbd)(uint8_t, uint8_t);
typedef void (*cbt)(uint8_t, uint8_t);
typedef void (*cba)(uint8_t, uint8_t, uint8_t);
typedef void (*MenuFunction) (int8_t);

class Menu {
public:
    Menu() {
        updownFns[0] = updownNone;
        updownFns[1] = updownAlarmHours;
        updownFns[2] = updownAlarmMinutes;
        updownFns[3] = updownTimeHours;
        updownFns[4] = updownTimeMinutes;
    }

    static void Setup(cbd display, cbt setTime, cba setAlarm, uint8_t alarmHours, uint8_t alarmMinutes) {
        cbDisplay = display;
        cbSetTime = setTime;
        cbSetAlarms = setAlarm;
        alarmHours = alarmHours;
        alarmMinutes = alarmMinutes;
        cbSetAlarms(alarmHours, alarmMinutes);
    }
    // Используется для обратного вызова menu.UpDown(dir)
    static void UpDown(int8_t direction) {
        updownFn(direction);
    }
    // Используется для обратного вызова menu.Tab()
    static void Tab() {
        updownFnNum++;
        updownFn = updownFns[updownFnNum % 5];
    }

private:

    static void updownNone(int8_t direction) { }

    static void updownAlarmHours(int8_t direction) {
        alarmHours += direction;
        cbDisplay(alarmHours, alarmMinutes);
        cbSetAlarms(alarmHours, alarmMinutes);
    }

    static void updownAlarmMinutes(int8_t direction) {
        alarmMinutes += direction;
        cbDisplay(alarmHours, alarmMinutes);
        cbSetAlarms(alarmHours, alarmMinutes);
    }

    static void updownTimeHours(int8_t direction) {
        timeHours += direction;
        cbSetTime(timeHours, timeMinutes);
        cbDisplay(timeHours, timeMinutes);
    }

    static void updownTimeMinutes(int8_t direction) {
        timeMinutes += direction;
        cbSetTime(timeHours, timeMinutes);
        cbDisplay(timeHours, timeMinutes);
    }

    static uint8_t alarmHours, alarmMinutes, timeHours, timeMinutes;
    static uint8_t updownFnNum; // 0-Нет, 1-ТревогаH, 2-ТревогаM, 3-ВремяH, 4-ВремяM
    static cbd cbDisplay;
    static cbt cbSetTime;
    static cba cbSetAlarms;
    static MenuFunction updownFns[5];
    static MenuFunction updownFn;
};

uint8_t Menu::alarmHours = 0;
uint8_t Menu::alarmMinutes = 0;
uint8_t Menu::timeHours = 0;
uint8_t Menu::timeMinutes = 0;
uint8_t Menu::updownFnNum = 0;
cbd Menu::cbDisplay = NULL;
cbt Menu::cbSetTime = NULL;
cba Menu::cbSetAlarms = NULL;
MenuFunction Menu::updownFn = NULL;
// MenuFunction Menu::updownFns = {};

Но все равно код неверный. если вы посмотрите на подпись этого определения

typedef void (*cba)(uint8_t, uint8_t, uint8_t);

он принимает 3 параметра. Но внутри кода вы даете 2 параметра функции

cbSetAlarms(alarmHours, alarmMinutes)
,

Это опечатка, я исправил. Но ошибка та же. typedef void (*cba)(uint8_t, uint8_t);, @Andre

Это не опечатка, опечатка означает что-то другое. если вы измените typedef void (*cba)(uint8_t, uint8_t, uint8_t); to typedef void (*cba)(uint8_t, uint8_t); Код скомпилируется без ошибок, @Volkan Ünal

updownFns[0] = updownNone; Это дало: /tmp/cc3MHoSt.ltrans0.ltrans.o: в функции «глобальные конструкторы с ключом 65535_0_app.ino.cpp.o.4201»: <искусственный>:(.text.startup+0x144): неопределенная ссылка на Menu::updownFns' <искусственный>:(.text.startup+0x148): неопределенная ссылка на Menu::updownFns' collect2: ошибка: ld вернул 1 статус выхода статус выхода 1 Ошибка компиляции для платы Arduino Pro или Pro Mini., @Andre

Есть несколько проблем с вашим кодом. Вы можете использовать вот так Уберите инициализацию из ctor и инициализируйте статическую переменную снаружи. MenuFunction Menu::updownFns[] = {updownNone, updownAlarmHours, updownAlarmMinutes, updownTimeHours, updownTimeMinutes }; Но когда вы хотите использовать updownFns, это выдаст ошибки, потому что функция также является частной в этом контексте., @Volkan Ünal

Я инициализировал массив вне определения класса. Нет ошибок. Затем я использовал updownFns и никаких ошибок., @Andre

Да, я уже говорил об этом :), @Volkan Ünal