2

I have a class "Person" like so:

typedef void (*action)();
typedef std::unordered_map<int, action> keybindMap; // maps keycodes to functions

class Person {
    keybindMap keybinds;
    void doSomething();
}

I use this to call the functions at the right times:

iter = keybinds.find(event.key.keysym.sym); // event.key.keysym.sym is the key code
if (iter != keybinds.end())
{
    (*iter->second)(); // call whatever function that key is bound to.
}

To bind a key, I used keybinds.insert_or_assign(SDLK_a, doSomething). However, this doesn't work (because doSomething is non-static). How do I change the binding code and/or the (*iter->second)() part so that I can call something equivalent to person.doSomething?

1 Answer 1

3

A non-static method requires an object to call it on. An ordinary function pointer doesn't have room to hold a reference to an object.

If you change your map to hold std::function instead, you can then use std::bind() or a lambda to associate an object with a method pointer, eg:

using action = std::function<void()>;
using keybindMap = std::unordered_map<int, action>;

class Person {
    keybindMap keybinds;
    void doSomething();
};

... 

Person p, otherP; //must outlive the map...
p.keybinds[...] = [&otherP](){ otherP.doSomething(); } 

...

iter = keybinds.find(event.key.keysym.sym);
if (iter != keybinds.end()) {
    iter->second();
}

On the other hand, if all of the target methods are in the same class/object, you can use a plain method pointer instead of std::function, which will reduce some overhead, eg:

class Person {
    using action = void (Person::*)();
    using keybindMap = std::unordered_map<int, action>; 

    keybindMap keybinds;
    void doSomething();
};

... 

keybinds[...] = &Person::doSomething;

...

iter = keybinds.find(event.key.keysym.sym);
if (iter != keybinds.end()) {
    (this->*(iter->second))();
}
Sign up to request clarification or add additional context in comments.

6 Comments

To follow up, if you don't want to use std::function, the prototype for a method pointer (which is distinctively different from a function pointer) is ReturnType (ClassName::*)(Parameters). Its calling convention is (instance->*methodPointer)(parameters), if memory serves. std::function is far easier though.
How much overhead does std::function really incur?
The second code doesn't run; the compiler says that Person isn't defined in this scope at the first line.
@Thuong I have updated my example
@ThuongVo: "How much overhead does std::function really incur?" Similar to a virtual call for operator() and for destruction. (and allocation if you pass "big" object).
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.