C++ 使用函数指针的STL映射

C++ 使用函数指针的STL映射,c++,stl,map,function-pointers,C++,Stl,Map,Function Pointers,我开发了一个脚本引擎,它有许多内置函数,所以要调用任何函数,我的代码都会变成if。。否则。。否则,如果wall检查名称,我想开发一个更有效的解决方案 我应该使用字符串作为键、指针作为值的hashmap吗?我如何使用STL映射来实现这一点 编辑: 我想到的另一点是:当然,使用映射会迫使编译器不内联函数,但我低效的方法没有因函数调用的必要性而产生任何开销,它只是执行代码 因此,我想知道函数调用产生的开销是否会比使用if..else链更好。。否则,我可以通过在运行时检查字符来减少比较次数(会更长但更快

我开发了一个脚本引擎,它有许多内置函数,所以要调用任何函数,我的代码都会变成
if。。否则。。否则,如果
wall检查名称,我想开发一个更有效的解决方案

我应该使用字符串作为键、指针作为值的hashmap吗?我如何使用STL映射来实现这一点

编辑: 我想到的另一点是:当然,使用映射会迫使编译器不内联函数,但我低效的方法没有因函数调用的必要性而产生任何开销,它只是执行代码


因此,我想知道函数调用产生的开销是否会比使用
if..else
链更好。。否则,我可以通过在运行时检查字符来减少比较次数(会更长但更快)。

无论函数签名是什么:

typedef void (*ScriptFunction)(void); // function pointer type
typedef std::unordered_map<std::string, ScriptFunction> script_map;

// ...

void some_function()
{
}

// ...

script_map m;
m.emplace("blah", &some_function);

// ...

void call_script(const std::string& pFunction)
{
    auto iter = m.find(pFunction);
    if (iter == m.end())
    {
        // not found
    }

    (*iter->second)();
}
typedef void(*ScriptFunction)(void);//函数指针类型
typedef std::无序映射脚本映射;
// ...
使某些函数无效()
{
}
// ...
脚本映射m;
m、 安置(“废话”和一些功能);
// ...
void call_脚本(const std::string和pffunction)
{
自动iter=m.find(pFunction);
如果(iter==m.end())
{
//找不到
}
(*国际热核实验堆->第二次)();
}

请注意,
ScriptFunction
类型可以泛化为
std::function
,因此您可以支持任何可调用的东西,而不仅仅是函数指针。

好的,您可以使用
any\u map
来存储具有不同签名的函数(但调用它会很麻烦)您可以使用
int\u map
调用具有特定签名的函数(看起来更好)

int FuncA()
{
返回1;
}
浮点数FuncB()
{
返回2;
}
int main()
{
//整数映射
地图国际地图;
int_map[“A”]=FuncA;
//叫它
cout您还可以使用甚至在某种程度上允许您拥有异构功能的映射:

typedef boost::function<void, void> fun_t;
typedef std::map<std::string, fun_t> funs_t;
funs_t f;

void foo() {}
void goo(std::string& p) {}
void bar(int& p) {}

f["foo"] = foo;
f["goo"] = boost::bind(goo, "I am goo");
f["bar"] = boost::bind(bar, int(17));
typedef boost::函数乐趣;
typedef标准::地图功能;
funs_t f;
void foo(){}
voidgoo(std::string&p){}
空条(int&p){}
f[“foo”]=foo;
f[“goo”]=boost::bind(goo,“我是goo”);
f[“bar”]=boost::bind(bar,int(17));

当然,它也可以是兼容原型的功能图。

上述答案似乎给出了一个完整的概述,这只涉及第二个问题:

按键检索映射元素的复杂度为O(logn)。按键检索Hashmap的复杂度为O(1)并且在发生冲突的情况下会增加一些内容。因此,如果函数名有一个好的哈希函数,请使用它。您的实现将有一个标准的。应该可以

但请注意,低于100个元素的任何元素都不会带来太多好处

哈希映射唯一的缺点是冲突。在您的情况下,哈希映射将是相对静态的。您知道您支持的函数名。因此,我建议您创建一个简单的测试用例,在该测试用例中,您使用所有键调用无序的\u map::hash\u函数,以确保没有冲突。之后,您可以忘记它

通过谷歌快速搜索哈希函数的潜在改进,我达到了目的:


也许,根据您的命名约定,您可以在函数的某些方面进行改进。

我尝试在c++11中使用第二个答案。我不得不更改最后一行 发件人:
(*iter)(;
致:
(*国际热核实验堆->第二次)()

因此,代码现在是:

    #include <map>

    typedef void (*ScriptFunction)(void); // function pointer type
    typedef std::map<std::string, ScriptFunction> script_map;

    // ...

    void some_function(void)
    {
    }
    script_map m;

    void call_script(const std::string& pFunction)
    {
        script_map::const_iterator iter = m.find(pFunction);
        if (iter == m.end())
        {
            // not found
        }
        (*iter->second)();
    }

    int main(int argc, const char * argv[])
    {
        //..
        m.insert(std::make_pair("blah", &some_function));

        call_script("blah");
        //..
        return 0;
    }
#包括
typedef void(*ScriptFunction)(void);//函数指针类型
typedef std::映射脚本\映射;
// ...
void某些函数(void)
{
}
脚本映射m;
void call_脚本(const std::string和pffunction)
{
脚本映射::常量迭代器iter=m.find(pffunction);
如果(iter==m.end())
{
//找不到
}
(*国际热核实验堆->第二次)();
}
int main(int argc,const char*argv[]
{
//..
m、 插入(std::make_pair(“blah”和一些_函数));
调用脚本(“废话”);
//..
返回0;
}

在C++11中,可以执行以下操作: 这个接口只需要返回类型,它负责调用方的所有其他操作

#include <string>
#include <iostream>
#include <map>
#include <vector>
#include <typeinfo>
#include <typeindex>
#include <cassert>

void fun1(void){
    std::cout<<"inside fun1\n";
}

int fun2(){
    std::cout<<"inside fun2\n";
    return 2;
}

int fun3(int a){
    std::cout<<"inside fun3\n";
    return a;
}

std::vector<int> fun4(){
    std::cout<<"inside fun4\n";
    std::vector<int> v(4,100);
    return v;
}

// every function pointer will be stored as this type
typedef void (*voidFunctionType)(void); 

struct Interface{

    std::map<std::string,std::pair<voidFunctionType,std::type_index>> m1;

    template<typename T>
    void insert(std::string s1, T f1){
        auto tt = std::type_index(typeid(f1));
        m1.insert(std::make_pair(s1,
                        std::make_pair((voidFunctionType)f1,tt)));
    }

    template<typename T,typename... Args>
    T searchAndCall(std::string s1, Args&&... args){
        auto mapIter = m1.find(s1);
        /*chk if not end*/
        auto mapVal = mapIter->second;

        // auto typeCastedFun = reinterpret_cast<T(*)(Args ...)>(mapVal.first); 
        auto typeCastedFun = (T(*)(Args ...))(mapVal.first); 

        //compare the types is equal or not
        assert(mapVal.second == std::type_index(typeid(typeCastedFun)));
        return typeCastedFun(std::forward<Args>(args)...);
    }
};

int main(){
    Interface a1;
    a1.insert("fun1",fun1);
    a1.insert("fun2",fun2);
    a1.insert("fun3",fun3);
    a1.insert("fun4",fun4);

    a1.searchAndCall<void>("fun1");
    int retVal = a1.searchAndCall<int>("fun3",2);
    a1.searchAndCall<int>("fun2");
    auto temp = a1.searchAndCall<std::vector<int>>("fun4");

    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
无效fun1(无效){

std::cout我已经设法修改了用于成员函数指针的:

#include <string>
#include <iostream>
#include <map>
#include <vector>
#include <typeinfo>
#include <typeindex>
#include <cassert>


template <typename A>
using voidFunctionType = void (A::*)(void);

template <typename A>
struct Interface{

    std::map<std::string,std::pair<voidFunctionType<A>,std::type_index>> m1;

    template<typename T>
    void insert(std::string s1, T f1){
        auto tt = std::type_index(typeid(f1));
        m1.insert(std::make_pair(s1,
                        std::make_pair((voidFunctionType<A>)f1,tt)));
    }

    template<typename T,typename... Args>
    T searchAndCall(A a, std::string s1, Args&&... args){
        auto mapIter = m1.find(s1);
        auto mapVal = mapIter->second;  

        auto typeCastedFun = (T(A::*)(Args ...))(mapVal.first); 

        assert(mapVal.second == std::type_index(typeid(typeCastedFun)));
        return (a.*typeCastedFun)(std::forward<Args>(args)...);
    }
};

class someclass {
    public:
        void fun1(void);
        int fun2();
        int fun3(int a);
        std::vector<int> fun4();
};

void someclass::fun1(void){
    std::cout<<"inside fun1\n";
}

int someclass::fun2(){
    std::cout<<"inside fun2\n";
    return 2;
}

int someclass::fun3(int a){
    std::cout<<"inside fun3\n";
    return a;
}

std::vector<int> someclass::fun4(){
    std::cout<<"inside fun4\n";
    std::vector<int> v(4,100);
    return v;
}

int main(){
    Interface<someclass> a1;
    a1.insert("fun3",&someclass::fun3);
     someclass s;
    int retVal = a1.searchAndCall<int>(s, "fun3", 3);
    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
模板
使用voidFunctionType=void(A::*)(void);
模板
结构接口{
std::map m1;
模板
无效插入(标准::字符串s1,T f1){
自动tt=std::类型索引(类型ID(f1));
m1.插入件(标准::形成配对(s1,
std::make_pair((voidFunctionType)f1,tt));
}
模板
T searchAndCall(A,std::string s1,Args&&…Args){
自动映射器=m1.查找(s1);
自动映射值=映射器->秒;
auto-typeCastedFun=(T(A::*)(Args…)(mapVal.first);
断言(mapVal.second==std::type_索引(typeid(typeCastedFun));
返回(a.*typeCastedFun)(std::forward(args)…);
}
};
上课{
公众:
void fun1(void);
int fun2();
int fun3(int a);
std::vector fun4();
};
void someclass::fun1(void){

std::cout我尝试将示例修改为类成员的接口,并将调用包装为searchAndCall,但函数fun1堆栈内部已损坏,a和b变量错误 实际上,它在assert
assert(mapVal.second==std::type_index(typeid(typeCastedFun));
上失败,因为不同的类型 如何正确地编写包装器

template <typename A>
using voidFunctionType = void (A::*)(void);

template <typename A>
struct Interface {

    std::map<std::string, std::pair<voidFunctionType<A>, std::type_index>> m1;

    template<typename T>
    void insert(std::string s1, T f1) {
        auto tt = std::type_index(typeid(f1));
        m1.insert(std::make_pair(s1,
            std::make_pair((voidFunctionType<A>)f1, tt)));
    }

    template<typename T, typename... Args>
    T searchAndCall(A* a, std::string s1, Args&&... args) {
        auto mapIter = m1.find(s1);
        auto mapVal = mapIter->second;

        auto typeCastedFun = (T(A::*)(Args ...))(mapVal.first);
        auto type = std::type_index(typeid(typeCastedFun));
        assert(mapVal.second == std::type_index(typeid(typeCastedFun)));
        return (a->*typeCastedFun)(std::forward<Args>(args)...);
    }
};
class someclass2
{
    Interface<someclass2> a1;
public:
    someclass2()
    {
        a1.insert("fun1", &someclass2::fun1);
    }
    int fun1(int a, int b)
    {
        return a + b;
    }
    void masterfunction(int a, int b)
    {
        int result =  a1.searchAndCall<int>(this, "fun1", a,b);
        std::cout << "Result " << result << std::endl;
    }
};
int main()
{
    someclass2 s1;
    s1.masterfunction(1, 2);
    return 0;
}
模板
使用voidFunctionType=void(A::*)(void);
模板
结构接口{
std::map m1;
模板
无效插入(标准::字符串s1,T f1){
自动tt=std::类型索引(类型ID(f1));
m1.插入件(标准::形成配对(s1,
std::make_pair((voidFunctionType)f1,tt));
}
模板
T searchAndCall(A*A,std::string s1,
template <typename A>
using voidFunctionType = void (A::*)(void);

template <typename A>
struct Interface {

    std::map<std::string, std::pair<voidFunctionType<A>, std::type_index>> m1;

    template<typename T>
    void insert(std::string s1, T f1) {
        auto tt = std::type_index(typeid(f1));
        m1.insert(std::make_pair(s1,
            std::make_pair((voidFunctionType<A>)f1, tt)));
    }

    template<typename T, typename... Args>
    T searchAndCall(A* a, std::string s1, Args&&... args) {
        auto mapIter = m1.find(s1);
        auto mapVal = mapIter->second;

        auto typeCastedFun = (T(A::*)(Args ...))(mapVal.first);
        auto type = std::type_index(typeid(typeCastedFun));
        assert(mapVal.second == std::type_index(typeid(typeCastedFun)));
        return (a->*typeCastedFun)(std::forward<Args>(args)...);
    }
};
class someclass2
{
    Interface<someclass2> a1;
public:
    someclass2()
    {
        a1.insert("fun1", &someclass2::fun1);
    }
    int fun1(int a, int b)
    {
        return a + b;
    }
    void masterfunction(int a, int b)
    {
        int result =  a1.searchAndCall<int>(this, "fun1", a,b);
        std::cout << "Result " << result << std::endl;
    }
};
int main()
{
    someclass2 s1;
    s1.masterfunction(1, 2);
    return 0;
}