¿Cómo almacenar objetos funcionales con diferentes firmas en un contenedor?

Entonces imaginemos que teníamos 2 funciones (void : ( void ) ) y (std::string : (int, std::string)) y podríamos tener 10 más. Todos (o algunos de ellos) toman diferentes tipos de argumentos y pueden devolver diferentes tipos. Queremos almacenarlos en un std::map , por lo que obtenemos una API como esta:

 //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("my_method_hello", hello_world) ) myMap.insert(std::pair("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"]; 

Me pregunto cómo poner muchas funciones diferentes en el mismo contenedor. Específicamente, cómo hacer esto en C ++ 03 usando Boost.

La API debe ser independiente de los tipos de funciones reales (teniendo int a = myMap["my_method_hello"]("Tim", 25); no int a = myMap["my_method_hello"]("Tim", 25); ).

 #include  #include  #include  #include  class api { // maps containing the different function pointers typedef void(*voidfuncptr)(); typedef int(*stringcrintptr)(std::string, const int&); std::map voida; std::map 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); } }; 

Uso:

 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 No es muy bonito. Un mejor consejo es no hacer nada ni remotamente como lo que sea que estés tratando de hacer.

Tenga en cuenta que esto requiere que todas las funciones con los mismos parámetros devuelvan el mismo tipo.

Puedes usar boost :: any …

 #include  #include  #include  #include  void voidFunc() { std::cout << "void called" << std::endl; } void stringFunc(std::string str) { std::cout << str << std::endl; } int main() { std::map funcs; funcs.insert(std::pair("voidFunc", &voidFunc)); funcs.insert(std::pair("stringFunc", &stringFunc)); boost::any_cast(funcs["voidFunc"])(); boost::any_cast(funcs["stringFunc"])("hello"); return 0; } 

Tenga en cuenta que obtendrá una excepción de tiempo de ejecución si no especifica correctamente la firma de la función en any_cast.

El caso es que, de alguna manera, cuando llamas a tus funciones, ya sabes qué tipo serán.

Si hacemos algo como

 int x = map["key"](1, "2") 

ya podemos deducir que cualquiera que sea la función almacenada en “clave” es de tipo (int (*)(int, char*)) así que bien podríamos haber hecho algo así como

 int x = map_of_int_and_string_to_int["key"](1, "2"); 

y evite toda la molestia de fusionar todas las claves juntas … Si bien es cierto que C ++ tiene algunas funciones de sobrecarga precisamente para este tipo de cosas, realmente no puedo ver por qué debería molestarse en este caso en particular.

Y al final, ¿por qué querrías poner todas esas funciones en el mismo mapa en primer lugar? No comparten ninguna interfaz similar, por lo que no puede acceder de forma uniforme a ellas, no puede iterar sobre ellas y no puede pasarlas de forma opaca a otra persona. Sin nada en común, no hay nada que pueda hacer con seguridad en las funciones de este mapa hipotético.

Puedes hacerlo lanzando punteros a las funciones para anular los punteros y volver. Se espera que conozcas la firma durante el tiempo de ejecución, por lo que no sería un problema el cablear a los operadores de conversión. Sin embargo, la lógica de hacerlo se me escapa. No tiene ningún sentido, al menos en C ++. El uso de clases / funciones de plantilla o estructuras de indicadores de función tiene mucho más sentido.

por ejemplo, con plantillas:

 template  foo(X param1) { /* do something with param1*/}; template  foo(X param1, Y param2) {/* do something with 2 params*/}; template  foo(X param1) { /* only one parameter, which is int */}; 

ahora:

 foo(5); // calls the third one foo("5"); // calls the first one foo("5", 5); // calls the second one. 

¿Quién necesita un mapa?