如何在 C++ 中按名称(std::string)调用函数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19473313/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 22:52:24  来源:igfitidea点击:

How to call a function by its name (std::string) in C++?

c++stringfunctioninvokecode-cleanup

提问by Alan Valejo

I wonder if there is a simple way to call a function from a string. I know a simple way, using 'if' and 'else'.

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

This is the basic approach

这是基本方法

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);
}

Is there something simpler?

有没有更简单的?

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

回答by LihO

What you have described is called reflectionand C++ doesn't support it. However you might come with some work-around, for example in this very concrete case you might use an std::mapthat would map names of functions (std::stringobjects) to function pointers, which in case of functions with the very same prototype could be easier than it might seem:

您所描述的称为反射,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;
}

Note that myMap[s](2,3)retrieves the function pointer mapped to string sand invokes this function, passing 2and 3to it, making the output of this example to be 5

请注意,myMap[s](2,3)检索映射到字符串的函数指针s并调用此函数,将2和传递3给它,使此示例的输出为5

回答by Martin York

Using a map of standard string to standard functions.

使用标准字符串到标准函数的映射。

#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";
}

Even better with Lambda:

使用 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";
}

回答by DarthGizka

There is another possibility which hasn't been mentioned yet, which is truereflection.

还有一种可能,还没有提到,就是真实的反映。

An option for this is accessing functions exported from an executable or a shared library using operating system functions for resolving names to addresses. This has interesting uses like loading two 'contestant' dlls into an 'umpire' program, so that people can slug it out by having their actual codes fight each other (playing Reversi or Quake, whatever).

一个选项是访问从可执行文件或共享库导出的函数,使用操作系统函数将名称解析为地址。这有一些有趣的用途,比如将两个“参赛者”dll 加载到“裁判”程序中,这样人们就可以通过让他们的实际代码相互竞争(玩黑白棋或地震,等等)来将其淘汰。

Another option is accessing the debug information created by the compiler. Under Windows this can be surprisingly easy for compilers that are compatible, since all the work can be off-loaded to system dlls or free dlls downloadable from Microsoft. Part of the functionality is already contained in the Windows API.

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

However, that falls more into the category of Systems Programming - regardless of language - and thus it pertains to C++ only insofar as it is the Systems Programming language par excellence.

然而,这更多地属于系统编程的范畴——不管语言如何——因此它只与 C++ 相关,因为它是卓越的系统编程语言。

回答by jav

You can also put your functions into a shared library. You will load such library dynamically with dlopen() and then just make the calls to the functions with a std::string. Here an example:

您还可以将您的函数放入共享库中。您将使用 dlopen() 动态加载此类库,然后使用 std::string 调用函数。这里有一个例子:

hello.cpp

你好.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

and:

和:

g++ main.cpp -o main -ldl

run:

跑:

C++ dlopen demo

Opening hello.so...
Loading symbol hello...
Calling hello...
hello
Closing library...

The example was stolen from here. Thereyou can find more detailed explanation on dlopen() and c++

这个例子是从这里来的在那里你可以找到关于 dlopen() 和 c++ 的更详细的解释