sirve - ¿Cómo llamar a una función por su nombre(std:: string) en C++?
string compare c# (4)
Me pregunto si hay una forma simple de llamar a una función desde una cadena. Lo sé de una manera simple, usando ''si'' y ''más''.
int function_1(int i, int j) {
return i*j;
}
int function_2(int i, int j) {
return i/j;
}
...
...
...
int function_N(int i, int j) {
return i+j;
}
int main(int argc, char* argv[]) {
int i = 4, j = 2;
string function = "function_2";
cout << callFunction(i, j, function) << endl;
return 0;
}
Este es el enfoque básico.
int callFunction(int i, int j, string function) {
if(function == "function_1") {
return function_1(i, j);
} else if(function == "function_2") {
return function_2(i, j);
} else if(...) {
} ...
...
...
...
return function_1(i, j);
}
¿Hay algo más simple?
/* New Approach */
int callFunction(int i, int j, string function) {
/* I need something simple */
return function(i, j);
}
Hay otra posibilidad que aún no se ha mencionado, que es la verdadera reflexión.
Una opción para esto es acceder a las funciones exportadas desde un ejecutable o una biblioteca compartida utilizando las funciones del sistema operativo para resolver nombres en direcciones. Esto tiene usos interesantes, como cargar dos dlls de ''concursantes'' en un programa ''umpire'', para que las personas puedan atacarlas haciendo que sus códigos reales luchen entre sí (jugando Reversi o Quake, lo que sea).
Otra opción es acceder a la información de depuración creada por el compilador. Bajo Windows, esto puede ser sorprendentemente fácil para los compiladores que son compatibles, ya que todo el trabajo se puede descargar a las dlls del sistema o dlls gratuitas que se pueden descargar desde Microsoft. Parte de la funcionalidad ya está contenida en la API de Windows.
Sin embargo, eso cae más en la categoría de Programación de Sistemas, independientemente del idioma, y por lo tanto, pertenece a C ++ solo en la medida en que es el lenguaje de Programación de Sistemas por excelencia.
Lo que has descrito se llama reflexión y C ++ no lo admite. Sin embargo, puede venir con una solución alternativa, por ejemplo, en este caso muy concreto, puede usar un std::map
que asignaría nombres de funciones ( std::string
objetos) a punteros de función, que en el caso de funciones con El mismo prototipo podría ser más fácil de lo que parece:
#include <iostream>
#include <map>
int add(int i, int j) { return i+j; }
int sub(int i, int j) { return i-j; }
typedef int (*FnPtr)(int, int);
int main() {
// initialization:
std::map<std::string, FnPtr> myMap;
myMap["add"] = add;
myMap["sub"] = sub;
// usage:
std::string s("add");
int res = myMap[s](2,3);
std::cout << res;
}
Tenga en cuenta que myMap[s](2,3)
recupera el puntero de función asignado a la cadena s
e invoca esta función, pasándole 2
y 3
, lo que hace que la salida de este ejemplo sea 5
También puede poner sus funciones en una biblioteca compartida. Cargará dicha biblioteca dinámicamente con dlopen () y luego solo hará las llamadas a las funciones con una cadena std ::. Aquí un ejemplo:
hola.cpp
#include <iostream>
extern "C" void hello() {
std::cout << "hello" << ''/n'';
}
main.cpp
#include <iostream>
#include <dlfcn.h>
int main() {
using std::cout;
using std::cerr;
cout << "C++ dlopen demo/n/n";
// open the library
cout << "Opening hello.so.../n";
void* handle = dlopen("./hello.so", RTLD_LAZY);
if (!handle) {
cerr << "Cannot open library: " << dlerror() << ''/n'';
return 1;
}
// load the symbol
cout << "Loading symbol hello.../n";
typedef void (*hello_t)();
// reset errors
dlerror();
std::string yourfunc("hello"); // Here is your function
hello_t hello = (hello_t) dlsym(handle, yourfunc.c_str());
const char *dlsym_error = dlerror();
if (dlsym_error) {
cerr << "Cannot load symbol ''hello'': " << dlsym_error <<
''/n'';
dlclose(handle);
return 1;
}
// use it to do the calculation
cout << "Calling hello.../n";
hello();
// close the library
cout << "Closing library.../n";
dlclose(handle);
}
Compilacion:
g++ -fPIC -shared hello.cpp -o hello.so
y:
g++ main.cpp -o main -ldl
correr:
C++ dlopen demo
Opening hello.so...
Loading symbol hello...
Calling hello...
hello
Closing library...
El ejemplo fue robado desde here . There puede encontrar una explicación más detallada sobre dlopen () y c ++
Usando un mapa de cadena estándar para funciones estándar.
#include <functional>
#include <map>
#include <string>
#include <iostream>
int add(int x, int y) {return x+y;}
int sub(int x, int y) {return x-y;}
int main()
{
std::map<std::string, std::function<int(int,int)>> funcMap =
{{ "add", add},
{ "sub", sub}
};
std::cout << funcMap["add"](2,3) << "/n";
std::cout << funcMap["sub"](5,2) << "/n";
}
Aún mejor con Lambda:
#include <functional>
#include <map>
#include <string>
#include <iostream>
int main()
{
std::map<std::string, std::function<int(int,int)>> funcMap =
{{ "add", [](int x, int y){return x+y;}},
{ "sub", [](int x, int y){return x-y;}}
};
std::cout << funcMap["add"](2,3) << "/n";
std::cout << funcMap["sub"](5,2) << "/n";
}