C++ 如何在C+中通过函数名(std::string)调用函数+;?

C++ 如何在C+中通过函数名(std::string)调用函数+;?,c++,string,function,invoke,code-cleanup,C++,String,Function,Invoke,Code Cleanup,我想知道是否有一种从字符串调用函数的简单方法。我知道一个简单的方法,用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

我想知道是否有一种从字符串调用函数的简单方法。我知道一个简单的方法,用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;
}
有更简单的吗

/* New Approach */
int callFunction(int i, int j, string function) {
    /* I need something simple */
    return function(i, j);
}

你所说的被称为<强>反射,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;
}
#包括
#包括
intadd(inti,intj){返回i+j;}
intsub(inti,intj){返回i-j;}
类型定义内部(*FnPtr)(内部,内部);
int main(){
//初始化:
std::map myMap;
myMap[“添加”]=添加;
myMap[“sub”]=sub;
//用法:
std::字符串s(“add”);
int res=myMap[s](2,3);

std::cout使用标准字符串到标准函数的映射

#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";
}
#包括
#包括
#包括
#包括
intadd(intx,inty){返回x+y;}
intsub(intx,inty){返回x-y;}
int main()
{
std::map funcMap=
{{“添加”,添加},
{“sub”,sub}
};

std::cout还有另一种尚未提及的可能性,那就是真实的反射

一个选项是使用操作系统函数访问从可执行文件或共享库导出的函数,以将名称解析为地址。这有一些有趣的用途,比如将两个“竞争对手”DLL加载到“裁判员”程序中,这样人们就可以通过让实际代码相互争斗来解决问题(玩反转或地震,随便什么)

另一个选项是访问编译器创建的调试信息。在Windows下,这对于兼容的编译器来说非常容易,因为所有工作都可以卸载到系统DLL或从Microsoft下载的免费DLL。部分功能已包含在Windows API中


<>但是,这更属于系统编程的范畴——不管语言如何,因此它只属于C++,因为它是系统编程语言的佼佼者。

< P>你也可以把你的函数放到一个共享库中。然后用std::string调用函数。下面是一个示例:

你好,cpp

#include <iostream>

extern "C" void hello() {
    std::cout << "hello" << '\n';
}
以及:

运行:


该示例是从中窃取的。您可以在dlopen()上找到更详细的解释而c++

您可以使用std::function和初始值设定项列表语法稍微改进一下。@LokiAstari:
std::function
我想是c++11。@LihO:我喜欢您的方法。谢谢。@AlanValejo:可能您没有c++11支持。尝试
\include
,如果不起作用,尝试
\include
@AlanValejo:tr1代表技术报告,即使在C++11还不受支持的情况下,它也可能允许您使用一些C++11功能。但是,两个tr1都可能不可用。@AlanValejo:当然是:)在C++11中,许多事情变得更清晰了这似乎是我上面答案中缺少的一部分,这正是我的答案所做的,但方式不同:“使用操作系统函数将名称解析为地址”除了我的,我的是直接的,需要你自己的“算法”将字符串解码到一个地址。反射思想的要点是访问由编译器创建的元数据,而不必定义带有函数名和指针的表。除了导出的名称和调试符号外,还有RTTI(对于某些编译器),以及处理编译器创建的用于函数名和地址之间映射的.map文件等混合方法。JEDI项目为堆栈遍历执行此操作,但它也可以用于查找名称的地址。其思想是使用编译器生成的反映源代码的数据,而不必定义自己的t阿贝尔斯。
#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";
}
#include <iostream>

extern "C" void hello() {
    std::cout << "hello" << '\n';
}
#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...