将回调函数传递给 std::map 的最佳方法是什么?

What is the best way to pass callback function to std::map?

我正在尝试处理以下代码,但程序崩溃了:

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

using namespace std;

typedef void (*callBackMethod)(string);
class CTest
{
private:
    map<string, callBackMethod> mapMethod;

    void testMethod(string msg)
    {
        cout << msg << endl;
    }
public:
    CTest()
    {
        addFunction("AA", (callBackMethod) &CTest::testMethod);
    }
    void addFunction(string funName, callBackMethod methodName)
    {
        mapMethod[funName] = methodName;
    }
    callBackMethod getMethod(string funName)
    {
        auto fun = mapMethod.find(funName);
        if(fun == mapMethod.end()) { return nullptr; }
        return fun->second;
    }
    void runFunction(string funName)
    {
        getMethod(funName)("test");
    }

};

int main()
{
    CTest test;
    test.runFunction("AA");

    return 0;
}

我有一个要求,我需要将私有方法传递给地图。程序编译时出现警告:

converting from 'void (CTest::*)(std::__cxx11::string) {aka void (CTest::*)(std::__cxx11::basic_string<char>)}' to 'callBackMethod {aka void (*)(std::__cxx11::basic_string<char>)}'

当我执行它时,它崩溃了。

当我将回调方法移到 class 之外时,它起作用了。我的要求是使程序流成为这样(隐藏需要添加到地图的外部调用的方法)。

期待您的评论。

由于您想使用成员变量,因此您需要在 typedef:

中以不同方式指定签名

在 C++ Builder 中可以完成以下操作:

typedef void(__closure *callBackMethod)(string);

如果你这样做,我建议你保留一个指向成员所属对象的智能指针,这样你就可以在调用函数之前检查对象是否仍然有效,否则会导致应用程序崩溃。

__closure 关键字是一个 C++ Builder 扩展,用于解决使用完全限定成员名称的要求 source

为了处理全局函数和成员函数,我们有以下内容:

typedef void(__closure *callBackMethodMember)(string);
typedef void (*callBackMethodGlobal)(string);

/* And then on 2 overloaded functions */
void addFunction(string funName, callBackMethodMember methodName) {}
void addFunction(string funName, callBackMethodGlobal methodName) {}

如果需要同时指向CTest成员函数和自由函数,那么可以使用std::function<void(std::string)>.

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

using namespace std;

using callBackFunction = std::function<void(string)>;

void testFunction(string msg)
{
    cout << "[" << __PRETTY_FUNCTION__ << "] " << msg << endl;
}

class CTest
{
private:
    map<string, callBackFunction> mapMethod;

    void testMethod(string msg)
    {
        cout << "[" << __PRETTY_FUNCTION__ << "] " << msg << endl;
    }
public:
    CTest()
    {
        addFreeFunction("AA", testFunction);
        addMemberFunction("BB", &CTest::testMethod);
    }
    void addMemberFunction(string funName, void(CTest::*methodName)(string))
    {
        using std::placeholders::_1;
        mapMethod[funName] = std::bind(methodName, this, _1);
    }
    void addFreeFunction(string funName, void(*methodName)(string))
    {
        mapMethod[funName] = methodName;
    }
    callBackFunction getMethod(string funName)
    {
        auto fun = mapMethod.find(funName);
        if(fun == mapMethod.end()) { return nullptr; }
        return fun->second;
    }
    void runFunction(string funName)
    {
        getMethod(funName)("test");
    }

};

int main()
{
    CTest test;
    test.runFunction("AA");
    test.runFunction("BB");

    return 0;
}

请注意,CTest 必须根据传递的函数类型以不同的方式将元素插入到映射中,因为对于成员函数,您必须提供要为其调用的对象,this 在这个例子中。这是通过使用 std::bind.

实现的