Asad-ullah Khan
Asad-ullah Khan

Reputation: 1833

How to pass a function in a parameter and then call that function from an object

I have a Sprite class that has an int update(int key) method.

I also have another class (SpriteManager) that has a list of all Sprites. I want to add a method to this class that takes a method, and an int as an argument. I then want to iterate through this list and call that method on all of the objects. However, I cannot find any way to do this. I know how to pass function as parameters, and also how to call specific methods on objects out of context, but I don't know how to do both.

An example of using this method would be something like:

sm.tellSpritesToDoSomething(Sprite::update, 42);

Where sm is a SpriteManager.

Upvotes: 0

Views: 76

Answers (1)

tumdum
tumdum

Reputation: 2031

You should check std::bind, std::function and placeholders. And always remember that method itself is not enough, you need to pass object which will be used as this inside. For example

sm.tellSpritesToDoSomething(std::bind(&Sprite::update, _1, 42));

To other ways to do this are to use member function pointers (either explicitly or via templates):

#include <vector>
#include <algorithm>
#include <functional>

struct Sprite {
    int update(int i) { return i; }
};

struct SpriteManager {
    std::vector<Sprite> sprites;
    template <typename F>
    void tellSpritesToDoSomething(F f, int i) {
        for (auto& sprite: sprites)
        {
            (sprite.*f)(i);
        }
    }
    void tellSpritesToDoSomething2(int (Sprite::*f)(int), int i) {
        for (auto& sprite: sprites)
        {
            (sprite.*f)(i);
        }
    }
    void tellSpritesToDoSomething3(std::function<int(Sprite&)> f) {
        std::for_each(sprites.begin(), sprites.end(), f);
    }
};

int main() {
    SpriteManager sm;
    sm.sprites.emplace_back();
    sm.sprites.emplace_back();
    sm.sprites.emplace_back();
    sm.tellSpritesToDoSomething(&Sprite::update, 42);
    sm.tellSpritesToDoSomething2(&Sprite::update, 42);
    using std::placeholders::_1;
    sm.tellSpritesToDoSomething3(std::bind(&Sprite::update, _1, 42));
}

Upvotes: 4

Related Questions