简体   繁体   中英

FSM Using Member Function Pointers in C++

I have two questions: the first on the cause of the specific error I'm trying to solve here, the second on the validity of my approach to the problem.

I'm trying to create a state machine that uses member function pointers, and I'm lost in the details. Other Q/As on the member function pointer topic seem to deal with calling the member functions from outside the class, and advocate the use of std::function and std::bind. I also read the C++ FAQ on pointers to member functions which also gives examples of calling the member functions outside the class. I'm not entirely sure those examples apply to what I'm trying to do.

This state machine approach is general across what I'm trying to do for this embedded application (This is the first real application I've written in C++. If this approach is stupid, please help me toward a better solution.). The specific code below is for the MessageHandler class. The idea is each hardware communication port ISR will copy its contents to its own buffer, and then queue its own MessageHandler object to process. There's several communication interfaces, but the protocol is the same on all of them.

Some snippets from 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();

};

And some examples from MessageHandler.cpp:

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

Another from MessageHandler.cpp:

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

I don't understand why for the two member functions I provided I get errors with the function table calls: Error: expression preceding parentheses of apparent call must have (pointer-to-) function type

Isn't that what I provided? That is, how are the types of transferFunctionTable and stateFunctionTable not pointers to functions?

I think to fix this I have to make all the functions static and pass references/pointers to the MessageHandler object.

Thanks in advance for your help.

Did you mean:

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

A pointer-to-member has to be dereferenced using .* or ->* . You can't just apply the function-call operator to it.

Also, you have a problem with your array initialization. It needs to be

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

because the bare name of a member function doesn't decay to a pointer-to-member. You have to use the address-of operator & on a qualified name.

Of course, both these fixes need to be applied to both tables of member-function pointers.

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

should be

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM