我想知道是否有一种从字符串中调用函数的简单方法。我知道一种简单的方法,使用'if'和'else'。
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;
}
这是基本方法
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);
}
有什么更简单的东西吗?
/* New Approach */
int callFunction(int i, int j, string function) {
/* I need something simple */
return function(i, j);
}
答案 0 :(得分:43)
您所描述的内容称为 反射 ,C ++不支持它。但是,您可能会遇到一些解决方法,例如在这个非常具体的情况下,您可能会使用std::map
将函数名称(std::string
对象)映射到函数指针,如果函数具有同样的原型可能比看起来更容易:
#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;
}
注意myMap[s](2,3)
检索映射到字符串s
的函数指针并调用此函数,将2
和3
传递给它,使此示例的输出为5
答案 1 :(得分:21)
使用标准字符串映射到标准函数。
#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";
}
使用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";
}
答案 2 :(得分:4)
尚未提及另一种可能性,即真实反射。
此选项是使用操作系统函数访问从可执行文件或共享库导出的函数,以便将名称解析为地址。这有一些有趣的用途,例如将两个'参赛者'dll加载到'裁判'程序中,这样人们可以通过让他们的实际代码互相争斗来打击它(玩Reversi或Quake,无论如何)。
另一个选项是访问编译器创建的调试信息。在Windows下,这对于兼容的编译器来说非常容易,因为所有工作都可以卸载到系统dll或可从Microsoft下载的免费dll。部分功能已包含在Windows API中。
然而,这更多地属于系统编程的范畴 - 无论语言如何 - 因此它只适用于C ++,因为它是卓越的系统编程语言。
答案 3 :(得分:3)
您还可以将函数放入共享库中。您将使用dlopen()动态加载此类库,然后仅使用std :: string调用函数。这里是一个例子:
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);
}
编译:
g++ -fPIC -shared hello.cpp -o hello.so
和:
g++ main.cpp -o main -ldl
运行:
C++ dlopen demo
Opening hello.so...
Loading symbol hello...
Calling hello...
hello
Closing library...