简体   繁体   中英

Mapping a type to a function of that type in c++

Let's suppose I have a character that can have 1 out of 3 states at a time(crouching, jumping and walking). For each of the 3 states I have a function of type void() that does whatever they are assigned to. I also have an enum that stores the different states and a number for each state.

class Player {
private:
   enum State {
       crouching = 0,
       walking= 1,
       jumping = 2
   } state;
}

I also have an unordered map that is used to link the different states to their funtions.

class Player {
private:
   std::unordered_map<int, void(Player::*)()> stateToFunc;

   void playerJump(){ /* code here */ };
   void playerCrouch(){ /* code here */ };
   void playerWalk(){ /* code here */ };

   Player() {
        // other stuff
        stateToFunc[0] = playerCrouch;
        stateToFunc[1] = playerWalk;
        stateToFunc[2] = playerJump;
}

I made it so everytime I press a certain key, the state variable will update. My goal is so on each update I will call only the function stateToFunc[state] instead of checking manually with a switch statement. It gives me the following error:

 Error  C3867   'Player::gActivated': non-standard syntax; use '&' to create a pointer to member

If I use stateToFunc[0] = & playerCrouch; , it gives me other errors. What can I do to achieve this?

You need to do what the compiler tells you - use the & operator to get a pointer to a member method. You will also have to specify the class the methods belong to, eg:

class Player {
private:
   std::unordered_map<State, void(Player::*)()> stateToFunc;

   void playerJump(){ /* code here */ };
   void playerCrouch(){ /* code here */ };
   void playerWalk(){ /* code here */ };

   Player() {
        // other stuff
        stateToFunc[crouching] = &Player::playerCrouch;
        stateToFunc[walking] = &Player::playerWalk;
        stateToFunc[jumping] = &Player::playerJump;
    }

    ...
}

Then, to actually call the methods, you can use the ->* operator, like this:

void Player::doSomething()
{
    ...
    (this->*stateToFunc[state])();
    ...
}

Alternatively, use std::function instead, with either std::bind() or lambdas, eg:

class Player {
private:
   std::unordered_map<State, std::function<void()>> stateToFunc;

   void playerJump(){ /* code here */ };
   void playerCrouch(){ /* code here */ };
   void playerWalk(){ /* code here */ };

   Player() {
        // other stuff

        stateToFunc[crouching] = std::bind(&Player::playerCrouch, this);
        stateToFunc[walking] = std::bind(&Player::playerWalk, this);
        stateToFunc[jumping] = std::bind(&Player::playerJump, this);
        // or:
        stateToFunc[crouching] = [this](){ playerCrouch(); };
        stateToFunc[walking] = [this](){ playerWalk(); };
        stateToFunc[jumping] = [this](){ playerJump(); }
    }

    ...
}
void Player::doSomething()
{
    ...
    stateToFunc[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