Je me demande s'il existe un moyen simple d'appeler une fonction à partir d'une chaîne. Je connais un moyen simple, en utilisant "si" et "sinon".
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;
}
Ceci est l'approche de base
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);
}
Y a-t-il quelque chose de plus simple?
/* New Approach */
int callFunction(int i, int j, string function) {
/* I need something simple */
return function(i, j);
}
Ce que vous avez décrit s'appelle réflexion et C++ ne le prend pas en charge. Cependant, vous pouvez venir avec une solution de contournement, par exemple dans ce cas très concret, vous pouvez utiliser un std::map
Qui mapperait les noms des fonctions (std::string
Objets) aux pointeurs de fonction, qui en cas de les fonctions avec le même prototype pourraient être plus faciles qu'il n'y paraît:
#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;
}
Notez que myMap[s](2,3)
récupère le pointeur de fonction mappé sur la chaîne s
et appelle cette fonction, en lui passant 2
Et 3
, Ce qui rend la sortie de cet exemple être 5
Utilisation d'une carte de chaîne standard vers des fonctions standard.
#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";
}
Encore mieux avec 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";
}
Il existe une autre possibilité qui n'a pas encore été mentionnée, qui est la réflexion true.
Une option pour cela consiste à accéder aux fonctions exportées à partir d'un exécutable ou d'une bibliothèque partagée à l'aide des fonctions du système d'exploitation pour résoudre les noms en adresses. Cela a des utilisations intéressantes comme le chargement de deux dll `` compétiteurs '' dans un programme `` arbitre '', afin que les gens puissent s'en débarrasser en faisant combattre leurs codes réels (en jouant Reversi ou Quake, peu importe).
Une autre option consiste à accéder aux informations de débogage créées par le compilateur. Sous Windows, cela peut être étonnamment facile pour les compilateurs compatibles, car tout le travail peut être déchargé sur des DLL système ou des DLL gratuites téléchargeables auprès de Microsoft. Une partie de la fonctionnalité est déjà contenue dans l'API Windows.
Cependant, cela tombe davantage dans la catégorie de la programmation système - quel que soit le langage - et donc il ne concerne le C++ que dans la mesure où il est le langage de programmation système par excellence.
Vous pouvez également placer vos fonctions dans une bibliothèque partagée. Vous allez charger une telle bibliothèque dynamiquement avec dlopen () et ensuite juste faire les appels aux fonctions avec une chaîne std ::. Voici un exemple:
hello.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);
}
compilation:
g++ -fPIC -shared hello.cpp -o hello.so
et:
g++ main.cpp -o main -ldl
courir:
C++ dlopen demo
Opening hello.so...
Loading symbol hello...
Calling hello...
hello
Closing library...
L'exemple a été volé à ici . Là vous pouvez trouver des explications plus détaillées sur dlopen () et c ++