How do I get a shared function pointer as a private member of a C ++ class?

The game I'm making will have triggers. When a trigger collides with something, something will happen; If it is a door trigger, the player will move to a new area. If it is an explosion, then an explosion will occur. A chair trigger can make the player sit down.

I don't want to subclass every trigger. Each of them has quite important information, and each of them will be activated using a common interface. The only difference between the two is the collision routines.

The problem is that the functions themselves can have different signatures.

For example, the player move function requires several things.

void move_player(Environment *new_env, Player *player, int new_x, int new_y)

      

But the explosion trigger might just be

void explode()

      

I need a class that accepts move_player

and explode

.

Here I think the pseudocode should look like

class Trigger
{
    public:
        Trigger(function_pointer f) { fp = f; }
        void activate() { fp(); }

    private:
        func_pointer fp;
}

      

I thought initialization / usage would look something like this.

auto f = std::bind(move_player, new_environment, my_player, 0, 0);
Trigger tigger (f);
tigger.activate();

      

I tried to go into the std documentation and search other forums and also check the Boost documentation. I know how to use bind, and I'm sure it should work here, but I have no way of setting up a function pointer within a class to be alone about argument lists. A minimal working example would be awesome.

+3


source to share


3 answers


You can use std::function

in combination with std::bind

and variation patterns, for example like this:

class Trigger {
  std::function<void()> fp;
public:
  template<typename F, typename ...Args>
  Trigger(F f, Args... args) : fp(std::bind(f, args...)) { }
  void activate() { fp(); }
};

      



LIVE DEMO

+2


source


What you want to use here is std::function

. More specifically, std::function<void()>

. Also consider using lambda instead of binding:



auto f = [=]() { movie_player(new_environment, my_player, 0, 0); };

      

+2


source


While it is possible to solve this with std::function

and std::bind

and / or lambda functions, it is just compiler and template magic to create your own class - if you are into template magic then this is a must. But I believe it does not solve any problem [that needs a solution], and makes the code more difficult to track and debug (because sooner or later you will want to debug the player move trigger, most likely at least if you not MUCH smarter than me and I can write code that NEVER needs to be debugged). Setting a breakpoint to is std::function::operator()

pretty tricky to get right and only break when you want it, not when it is called from elsewhere (e.g. your lowercase std :: string conversion function that deals with the user) ..

In this case, I would say that a class Trigger

with a virtual function would be correct.

The class MovePlayer

[or if you want to name it move_player

] might look like this:

class MovePlayer : public Trigger
{
   MovePlayer(Player *p, int x, int y) : player(p), dx, dy) {}
   void Activate() override { player->SetPos(dx, dy); }
private:
   Player *player;
   int dx, dy;
};

      

[Of course you shouldn't use raw pointers - in that case use std::shared_ptr<Player>

and store std::weak_ptr<Player>

in MovePlayer

]

+2


source







All Articles