如何将具有不同签名的function对象存储在容器中?
所以想象我们有2个函数(void : ( void ) )
和(std::string : (int, std::string))
,我们可以有10个函数。 所有(或其中一些)都采用不同的参数types,并可以返回不同的types。 我们想把它们存储在一个std::map
,所以我们得到了这样一个API:
//Having a functions like: int hello_world(std::string name, const int & number ) { name += "!"; std::cout << "Hello, " << name << std::endl; return number; } //and void i_do_shadowed_stuff() { return; } //We want to be capable to create a map (or some type with similar API) that would hold our functional objects. like so: myMap.insert(std::pair<std::string, fun_object>("my_method_hello", hello_world) ) myMap.insert(std::pair<std::string, fun_object>("my_void_method", i_do_shadowed_stuff) ) //And we could call tham with params if needed: int a = myMap["my_method_hello"]("Tim", 25); myMap["my_void_method"];
我想知道如何把许多不同的function放在同一个容器中。 具体来说,如何在C ++ 03中使用Boost来做到这一点。
API应该与实际的函数types无关( int a = myMap["my_method_hello"]("Tim", 25);
不是int a = myMap<int, (std::string, int)>["my_method_hello"]("Tim", 25);
)。
#include <functional> #include <iostream> #include <string> #include <map> class api { // maps containing the different function pointers typedef void(*voidfuncptr)(); typedef int(*stringcrintptr)(std::string, const int&); std::map<std::string, voidfuncptr> voida; std::map<std::string, stringcrintptr> stringcrint; public: // api temp class // given an api and a name, it converts to a function pointer // depending on parameters used class apitemp { const std::string n; const api* p; public: apitemp(const std::string& name, const api* parent) : n(name), p(parent) {} operator voidfuncptr() { return p->voida.find(n)->second; } operator stringcrintptr() { return p->stringcrint.find(n)->second; } }; // insertion of new functions into appropriate maps void insert(const std::string& name, voidfuncptr ptr) { voida[name]=ptr; } void insert(const std::string& name, stringcrintptr ptr) { stringcrint[name]=ptr; } // operator[] for the name gets halfway to the right function apitemp operator[](std::string n) const { return apitemp(n, this); } };
用法:
api myMap; int hello_world(std::string name, const int & number ) { name += "!"; std::cout << "Hello, " << name << std::endl; return number; } int main() { myMap.insert("my_method_hello", &hello_world ); int a = myMap["my_method_hello"]("Tim", 25); }
http://ideone.com/SXAPu不是很漂亮。; 更好的build议是不要做任何事情,甚至不要像你正在做的那样做任何事情。
请注意,这要求具有相同参数的所有函数返回相同的types。
你可以使用boost :: any …
#include <boost/any.hpp> #include <iostream> #include <map> #include <string> void voidFunc() { std::cout << "void called" << std::endl; } void stringFunc(std::string str) { std::cout << str << std::endl; } int main() { std::map<std::string, boost::any> funcs; funcs.insert(std::pair<std::string, boost::any>("voidFunc", &voidFunc)); funcs.insert(std::pair<std::string, boost::any>("stringFunc", &stringFunc)); boost::any_cast<void(*)(void)>(funcs["voidFunc"])(); boost::any_cast<void(*)(std::string)>(funcs["stringFunc"])("hello"); return 0; }
请注意,如果您没有在any_cast中正确指定函数签名,您将得到一个运行时exception。
不pipe怎样,当你打电话给你的function时,你已经知道他们会是什么types的。
如果我们做类似的事情
int x = map["key"](1, "2")
我们已经可以推断出,“key”中存储的任何函数都是types(int (*)(int, char*))
所以我们可能做了类似
int x = map_of_int_and_string_to_int["key"](1, "2");
并避免将所有的键合并在一起的麻烦…虽然C ++有一些正是这种东西的重载特性是真的,我真的不明白为什么你应该打扰在这种特殊情况下。
最后,为什么要把所有这些function放在同一张地图上呢? 他们没有共享任何类似的接口,所以你不能统一访问它们,你不能遍历它们,你不能不透明地把它们传递给别人。 没有任何共同之处,没有什么可以安全地做到这个假设的地图的function。
你可以通过投射函数指针来void指针和返回。 在运行期间,您应该知道这个签名,所以这对硬连线的操作员来说不会是个问题。 然而,这样做的逻辑逃避了我。 至less在C ++中是没有任何意义的。 使用模板类/函数或函数指针的结构更有意义。
例如,使用模板:
template <typename X> foo(X param1) { /* do something with param1*/}; template <typename X, typename Y> foo(X param1, Y param2) {/* do something with 2 params*/}; template <int X> foo(X param1) { /* only one parameter, which is int */};
现在:
foo(5); // calls the third one foo("5"); // calls the first one foo("5", 5); // calls the second one.
谁需要地图?