使用函数指针的STL映射

我开发了一个拥有许多内置函数的脚本引擎,所以要调用任何函数,我的代码就进入了if .. else if .. else if检查名称的墙,但我想开发一个更有效的解决scheme。

我应该使用散列表与string作为键和指针作为值? 我怎么能通过使用STL地图呢?

编辑 :进入我的脑海的另一点:当然使用地图将强制编译器不内联函数,但我低效率的方法没有任何开销产生的function调用的必要性,它只是执行代码。

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

无论您的function签名是什么:

 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)(); } 

请注意, ScriptFunctiontypes可以推广到std::function</* whatever*/>所以你可以支持任何可调用的东西,而不仅仅是函数指针。

你也可以使用Boost.Function和Boost.Bind甚至允许你在某种程度上拥有异构函数的映射:

 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)); 

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

上面的答案似乎给了一个完整的概述,这只是你的第二个问题:

按键检索地图元素具有O(log n)复杂性。 密钥的Hashmap检索具有O(1)复杂性+在冲突的情况下有一点点东西。 所以,如果你的函数名称有一个好的散列函数,那就使用它。 你的实现将有一个标准的。 应该没问题。

但请注意,百元以下的东西不会太多。

哈希映射唯一的缺点是碰撞。 在你的情况下,hashmap将是相对静态的。 你知道你支持的函数名称。 所以我build议你创build一个简单的testing用例,你可以用你所有的键调用unordered_map <…> :: hash_function来确保没有任何东西发生冲突。 之后,你可以忘记它。

一个快速谷歌潜在的改进散列函数让我在那里:

一个很好的散列函数

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

在C ++ 11中,你可以做这样的事情:这个接口只需要返回types,并且处理来自呼叫方的所有其他事情。

 #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; } 

那么,你可以使用any_map存储具有不同签名的函数(但调用它将是混乱的),你可以使用int_map来调用具有特定签名的函数(看起来更好)。

 int FuncA() { return 1; } float FuncB() { return 2; } int main() { // Int map map<string,int(*)()> int_map; int_map["A"] = FuncA; // Call it cout<<int_map["A"]()<<endl; // Add it to your map map<string, void(*)> any_map; any_map["A"] = FuncA; any_map["B"] = FuncB; // Call cout<<reinterpret_cast<float(*)()>(any_map["B"])()<<endl; } 

我试图用第二个答案与C + + 11。 我不得不改变最后一行:
(* ITER)();
至:
(* 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; }