Search code examples
c++pointer-to-member

C++ passing a member function as an argument to another member function


I want to pass a member method as an argument to another member method. I have researched this extensively but still can not see to get it correct. My header file is as follows

#include <string>
#include <map>
#include <functional>

#include "Entity.h"
#include "World.h"
#include "Item.h"

class Tile;

class Player : public Entity
{
private:
    using FunctionPointer = void (Player::*)(Tile*);
    bool victory;
    Point location;
    std::map<char, FunctionPointer> actions;

public:
    Player(std::string name, int gold, int maxHitPoints, int defensePoints, 
           Point startingLocation, int maxDamage = 0, int maxItems = -1,
           std::vector<Item*> inventory = std::vector<Item*>());

    std::string getClassName() const override;

    void printInventory(Tile*) override; 
    std::string toString() override;

    Point getLocation() const;
    Item* findMostPowerfulWeapon();
    void heal(Tile*);
    void moveNorth(Tile*);
    void moveSouth(Tile*);
    void moveEast(Tile*);
    void moveWest(Tile*);
    void attack(Tile* tile);
    void pickup(Tile* tile);
    void trade(Tile* tile);

    void getAvailableActions(Tile* tile);
    void chooseAction();

private:
    void move(int dx, int dy);
    void actionAdder(char hotkey, FunctionPointer, std::string name);
}; 

And a part of the cpp file that is giving me problems is as follows:

void Player::getAvailableActions(Tile * tile)
{
    actions.clear();
    std::cout << "Choose an action:" << std::endl;
    if (getInventory().size() > 0)
        actionAdder('i', (this->*(&Player::printInventory))(tile), "Print inventory");
    if (tile->getClassName() == "Trader")
        actionAdder('t', (this->*(&Player::trade))(tile) , "Trade");
    if (tile->getClassName() == "Monster")
        actionAdder('a', (this->*(&Player::attack))(tile), "Attack");
}

void Player::actionAdder(char hotkey, FunctionPointer action, std::string name)
{}

Visual studio marks the parenthesis in front of all three this, (this->*(&Player::attack))(tile), and gives the tool tip "argument of type "void" is incompatible with parameter of type "Player::FunctionPointer"". The compiler error that I get if I try to compile is 'void Player::actionAdder(char,Player::FunctionPointer,std::string)': cannot convert argument 2 from 'void' to 'Player::FunctionPointer'.

If anyone has any idea of what I am doing wrong I would be grateful for any suggestions. If you need to see more code or more details let me know. The code is not super secret.

Thanks


Solution

  • Read the error messages carefully:

    argument of type "void" is incompatible with parameter of type

    and

    cannot convert argument 2 from 'void' to 'Player::FunctionPointer'.

    That's because argument 2 here:

    actionAdder('i', (this->*(&Player::printInventory))(tile), "Print inventory");
    

    is actually invoking printInventory and trying to pass the result of that invocation into actionAdder(). But that's a void function, and you can't pass something of type void to something else - hence the error complaining about precisely that.

    You don't want to invoke printInventory, you just want to pass a pointer to it. That's just:

    actionAdder('i', &Player::printInventory, "Print inventory");