简体   繁体   English

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

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

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

What you have described is called reflection and C++ doesn't support it. 您所描述的称为反射,而C ++不支持它。 However you might come with some work-around, for example in this very concrete case you might use an std::map that would map names of functions ( std::string objects) to function pointers, which in case of functions with the very same prototype could be easier than it might seem: 但是,您可能会带来一些变通办法,例如,在这种非常具体的情况下,您可以使用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 s and invokes this function, passing 2 and 3 to it, making the output of this example to be 5 请注意, myMap[s](2,3)检索映射到字符串s的函数指针并调用此函数,将23传递给它,使本示例的输出为5

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

There is another possibility which hasn't been mentioned yet, which is true reflection. 尚未提及的另一种可能性是真实反映。

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加载到“裁判”程序中,这样人们就可以通过使他们的实际代码相互抗衡(玩Reversi或Quake,等等)来将其塞进去。

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. 在Windows下,这对于兼容的编译器来说可能非常容易,因为所有工作都可以卸载到系统dll或可从Microsoft下载的免费dll中。 Part of the functionality is already contained in the Windows API. 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 ++有关,因为它是卓越的系统编程语言。

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. 您将使用dlopen()动态加载此类库,然后仅使用std :: string调用函数。 Here an example: 这里是一个例子:

hello.cpp 你好

#include <iostream>

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

main.cpp 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 . 这个例子是从这里来的 There you can find more detailed explanation on dlopen() and c++ 在这里您可以找到有关dlopen()和c ++的更详细的解释

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM