C++ map of “events” and member function pointers

不羁的心 提交于 2019-12-20 06:21:28

问题


I've managed to write a template class to work like a callback, learned from the accepted answer of this question How to define a general member function pointer.

I wish to have a map of string keys and callback values so that I can invoke the proper callback that matches a string. This would be fine but I need the map to support callbacks from different classes. Right now it can only work with one class. It can be any class because of the template but only a collection of callbacks from the same class.

class Apple {
public:
    void Red () {
        cout << "aa";
    }
};

class Orange {
public:
    void Blue () {
        cout << "bb";
    }
};

template <typename T>
class Callback {
    T *obj;
    void (T::*ptr) (void);

public:
    Callback (T *obj, void (T::*ptr) (void)) : obj (obj), ptr (ptr) {

    }

    void Call () {
        (obj->*ptr) ();
    }
};

I can use this like so

Apple apple;
Orange orange;
Callback <Apple> callA (&apple, &Apple::Red);
Callback <Orange> callB (&orange, &Orange::Blue);
callA.call ();
callB.call ();

std::map <std::string, Callback <Apple>> appleCallbacks;

I want to be able to do this

std::map <std::string, Callback <anything>> anyCallbacks;

I plan to use this with a bunch of classes that share the same base class and have functions are identical to each other in definition except for the name and which class it belongs to.

class Base { };

class ChildA : public Base {
public:
    void Talk ();
}

class ChildB : public Base {
public:
    void Walk ();
}

So if this worked I would be able to put both Talk () and Walk () into the map.

Is this possible at all or is my point of view flawed to begin with?


回答1:


Madness lies, this way: Don't bind callbacks to specific classes. Instead, use a std::function<Signature> object and create suitable function objects: when you need to operate on different classes, you also need to operate on objects of different types. Using a std::function<...> should do the trick, e.g.:

std::map<std::string, std::function<void()>> operations;
operations["talk"] = std::bind(&ChildA::Talk, ChildA());
operations["walk"] = std::bind(&ChildB::Walk, ChildB());
operations["talk"]();



回答2:


There's no need for inheritance here. Just use std::function to store the member function pointers and std::bind to bind together the member function pointer and the object instance.

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

struct Apple {
    void Red () {
        std::cout << "aa\n";
    }
};

struct Orange {
    void Blue () {
        std::cout << "bb\n";
    }
};

int main()
{
    std::map<std::string, std::function<void()>> m;
    Apple a;
    Orange o;

    m["apple"] = std::bind(&Apple::Red, a);
    m["orange"] = std::bind(&Orange::Blue, o);

    m["apple"]();
    m["orange"]();
}

Output:

aa
bb


来源:https://stackoverflow.com/questions/19192130/c-map-of-events-and-member-function-pointers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!