FSM Использование указателей на функции-члены в C ++

0

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

Я пытаюсь создать конечный автомат, который использует указатели функций-членов, и я потерян в деталях. Другие вопросы о Q/As в тексте-элементе-члене, похоже, связаны с вызовом функций-членов из-за пределов класса и защищают использование std :: function и std :: bind. Я также читал FAQ C++ по указателям на функции-члены, которые также приводят примеры вызова функций-членов вне класса. Я не совсем уверен, что эти примеры относятся к тому, что я пытаюсь сделать.

Этот подход с государственным компьютером является общим для всего, что я пытаюсь сделать для этого встроенного приложения (это первое реальное приложение, которое я написал в C++. Если этот подход глуп, пожалуйста, помогите мне в более эффективном решении.). Указанный ниже код предназначен для класса MessageHandler. Идея заключается в том, что каждый аппаратный коммуникационный порт ISR копирует свое содержимое в собственный буфер, а затем ставит в очередь свой собственный объект MessageHandler для обработки. Там несколько интерфейсов связи, но протокол одинаковый для всех из них.

Некоторые фрагменты из MessageHandler.h:

class MessageHandler
{
private:
    enum state_t {
        WAIT_METADATA,
        WAIT_PAYLOAD,
        NUM_STATES
    };
    enum transfer_t {
        INPUT_PARTIAL_METADATA,
        INPUT_METADATA,
        INPUT_PARTIAL_PAYLOAD,
        INPUT_COMMAND,
        INPUT_TIMEOUT,
        INPUT_UNKNOWN,
        NUM_TRANSFER_INPUTS
    };

    typedef transfer_t (MessageHandler::*transferFunction)();
    transferFunction transferFunctionTable[NUM_STATES] = {
        checkMetadata,
        checkPayload
    };

    typedef state_t(MessageHandler::*stateFunction)();
    stateFunction stateFunctionTable[NUM_TRANSFER_INPUTS] = {
        gotPartialMetadata,
        gotMetadata,
        gotPartialPayload,
        gotCommand,
        gotTimeout,
        gotUnknownError
    };

    size_t processTable[NUM_TRANSFER_INPUTS][NUM_STATES] = {
        { 0, 5 },
        { 1, 5 },
        { 5, 2 },
        { 5, 3 },
        { 4, 4 },
        { 5, 5 }
    };

    ...

    state_t state;

    transfer_t getInput();
    transfer_t checkMetadata();
    transfer_t checkPayload();
    state_t gotPartialMetadata();
    state_t gotMetadata();
    state_t gotPartialPayload();
    state_t gotCommand();
    state_t gotTimeout();
    state_t gotUnknownError();

    ...

public:
    ...
    state_t process();

};

И некоторые примеры из MessageHandler.cpp:

MessageHandler::transfer_t MessageHandler::getInput()
{
    ...
    return transferFunctionTable[state]();
}

Другой из MessageHandler.cpp:

MessageHandler::state_t MessageHandler::process()
{
    do {
        state = stateFunctionTable[ processTable[getInput()][state] ]();
    } while (cbRemaining > 0);
}

Я не понимаю, почему для двух функций-членов, которые я предоставил, я получаю ошибки при Error: expression preceding parentheses of apparent call must have (pointer-to-) function type таблицы функций: Error: expression preceding parentheses of apparent call must have (pointer-to-) function type

Разве это не то, что я предоставил? То есть, как типы transferFunctionTable и stateFunctionTable не указывают на функции?

Я думаю, чтобы исправить это, я должен сделать все функции static и передать ссылки/указатели на объект MessageHandler.

Заранее спасибо за вашу помощь.

  • 0
    Указатели на функции-члены - это кошмар!
  • 0
    Что касается вашего общего подхода: Да, есть определенно лучшие способы приблизиться к ФСМ на ОО-языках. Например, хорошо известный государственный шаблон . Здесь вы можете найти библиотеку шаблонов, которая упрощает реализацию подхода FSM на основе шаблонов состояний: STTCL .
Показать ещё 5 комментариев
Теги:
pointers
c++11
fsm

2 ответа

0
Лучший ответ
MessageHandler::transfer_t MessageHandler::getInput()
{
    return transferFunctionTable[state]();
}

должно быть

MessageHandler::transfer_t MessageHandler::getInput()
{
    return (this->*transferFunctionTable[state])();
}
2

Ты имел ввиду:

MessageHandler::state_t MessageHandler::process()
{
    do {
        stateFunction stateAction = stateFunctionTable[ processTable[getInput()][state] ];
        state = (this->*stateAction)();
    } while (cbRemaining > 0);
}

Указатель-член должен быть разыменован с помощью .* Или ->*. Вы не можете просто применить к нему оператор функции-вызова.

Кроме того, у вас возникла проблема с инициализацией массива. Это должно быть

transferFunction transferFunctionTable[NUM_STATES] = {
    &MessageHandler::checkMetadata,
    &MessageHandler::checkPayload
};

потому что голое имя функции-члена не распадается на указатель-на-член. Вы должны использовать адрес-оператора & по квалифицированному имени.

Конечно, обе эти исправления должны применяться к обеим таблицам указателей на функции-члены.

  • 0
    Я думаю, что Jarod42 имеет правильную идею, то, что у вас есть выше, становится state = (this->*stateFunctionTable[ processTable[getInput()][state] ])(); , Разве typedef для TransferFunction не должен явно указывать указатель как указатель на функцию-член? Кажется, работает без него.
  • 0
    @Ditiris: Извините, я использовал неправильный typedef. Исправлена.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню