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

时间:2022-08-27 18:46:51

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

4 个解决方案

#1


36  

What you have described is called reflection and 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::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:

您所描述的是反射,c++不支持它。但是,您可能需要进行一些变通,例如,在这个非常具体的例子中,您可能使用std::map,它将函数名(std::string object)映射到函数指针,如果函数具有相同的原型,那么它可能比看起来更容易:

#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的函数指针并调用这个函数,将2和3传递给它,使本例的输出为5

#2


16  

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:

和λ更好:

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

#3


4  

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加载到一个“裁判”程序中,这样人们就可以通过让他们的实际代码互相争斗(玩黑棋棋棋棋棋棋或地震之类的)来进行攻击。

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或从微软下载的免费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++,因为它是最优秀的系统编程语言。

#4


0  

This is possible on a lower level if you intertwine assembly with c, and from there use a C++ compiler with C and then use C++ and that could be a form of reflection.

这在较低的层次上是可能的,如果你把程序集与c交织在一起,然后使用c++编译器与c编译,然后使用c++,这可能是一种反射形式。

The way it works is via the function addresses. Operating Systems randomize the addresses and then the variables may be placed accordingly such as heapAddress + 1, heapAddress + 2, etcetera. This works for functions as well.

它的工作方式是通过函数地址。操作系统将地址随机化,然后可以相应地放置变量,如heapAddress + 1、heapAddress + 2等等。这也适用于函数。

The DNS is the Domain Name Server in the world of the internet. It interprets a domain name such as http://www.example.com/ to an IP address, say perhaps 10.87.23.9/(IPs starting with 10 usually are private networks). You could use @LiHO's idea and create a map, but of the function addresses instead. Again, this is very low level, not even on the C++ level, and quite involved. With a map of the addresses, given a string you could perhaps decode it to an address via references to an array of long or int.

DNS是internet世界中的域名服务器。它解释了一个域名,例如http://www.example.com/到一个IP地址,大概是10.87.23.9/(IPs以10开头,通常是私有网络)。您可以使用@LiHO的想法创建一个映射,但是要使用函数地址。同样,这是非常低的级别,甚至在c++级别上都没有,而且非常复杂。使用地址的映射,给定一个字符串,您可以通过对一个长数组或int数组的引用将其解码为一个地址。

After decoding this to an address, you'll have to place the binary instructions into the CPU registers for execution. Whether you decide to use assembly or C to do the job depends on what you do. You could take an operand stack approach and use C to execute each instruction with it's parameters, or you can use assembly to place the instructions, the data, or both into a CPU's registers for execution.

在将它解码到一个地址之后,您必须将二进制指令放入CPU寄存器中执行。你决定用汇编还是C来做这个工作取决于你做什么。您可以采取操作和堆栈方法,使用C来执行每个指令,使用它的参数,或者您可以使用程序集将指令、数据或两者都放入CPU的寄存器中执行。

Here is how I would code it (provided this is pseudo-code):

这里是我如何编码它(假设这是伪代码):

language C/C++ header file:

语言C / c++头文件:

//reflection.h
#pragma once
class Reflection {
public:
   extern "C" {
     static void exec(int& func_addr);
   }
}

language C++:

语言c++:

//mysourcefile.cpp
#pragma once
#include "reflection.h"
#include "map.h"

int main(){
   Map map;
   Reflection.exec(map.decode("run()"); // executes a function called run() in the current class
   wait(10);//seconds
   return 0;
}

void run(){
 cout<<"This is now running via reflection from an assembly procedure in a C function in a C++      function!";
}

output:

输出:

This is now running via reflection from an assembly procedure in a C function in a C++ function!

现在,它通过c++函数中的C函数中的程序集反射运行!

#1


36  

What you have described is called reflection and 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::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:

您所描述的是反射,c++不支持它。但是,您可能需要进行一些变通,例如,在这个非常具体的例子中,您可能使用std::map,它将函数名(std::string object)映射到函数指针,如果函数具有相同的原型,那么它可能比看起来更容易:

#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的函数指针并调用这个函数,将2和3传递给它,使本例的输出为5

#2


16  

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:

和λ更好:

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

#3


4  

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加载到一个“裁判”程序中,这样人们就可以通过让他们的实际代码互相争斗(玩黑棋棋棋棋棋棋或地震之类的)来进行攻击。

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或从微软下载的免费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++,因为它是最优秀的系统编程语言。

#4


0  

This is possible on a lower level if you intertwine assembly with c, and from there use a C++ compiler with C and then use C++ and that could be a form of reflection.

这在较低的层次上是可能的,如果你把程序集与c交织在一起,然后使用c++编译器与c编译,然后使用c++,这可能是一种反射形式。

The way it works is via the function addresses. Operating Systems randomize the addresses and then the variables may be placed accordingly such as heapAddress + 1, heapAddress + 2, etcetera. This works for functions as well.

它的工作方式是通过函数地址。操作系统将地址随机化,然后可以相应地放置变量,如heapAddress + 1、heapAddress + 2等等。这也适用于函数。

The DNS is the Domain Name Server in the world of the internet. It interprets a domain name such as http://www.example.com/ to an IP address, say perhaps 10.87.23.9/(IPs starting with 10 usually are private networks). You could use @LiHO's idea and create a map, but of the function addresses instead. Again, this is very low level, not even on the C++ level, and quite involved. With a map of the addresses, given a string you could perhaps decode it to an address via references to an array of long or int.

DNS是internet世界中的域名服务器。它解释了一个域名,例如http://www.example.com/到一个IP地址,大概是10.87.23.9/(IPs以10开头,通常是私有网络)。您可以使用@LiHO的想法创建一个映射,但是要使用函数地址。同样,这是非常低的级别,甚至在c++级别上都没有,而且非常复杂。使用地址的映射,给定一个字符串,您可以通过对一个长数组或int数组的引用将其解码为一个地址。

After decoding this to an address, you'll have to place the binary instructions into the CPU registers for execution. Whether you decide to use assembly or C to do the job depends on what you do. You could take an operand stack approach and use C to execute each instruction with it's parameters, or you can use assembly to place the instructions, the data, or both into a CPU's registers for execution.

在将它解码到一个地址之后,您必须将二进制指令放入CPU寄存器中执行。你决定用汇编还是C来做这个工作取决于你做什么。您可以采取操作和堆栈方法,使用C来执行每个指令,使用它的参数,或者您可以使用程序集将指令、数据或两者都放入CPU的寄存器中执行。

Here is how I would code it (provided this is pseudo-code):

这里是我如何编码它(假设这是伪代码):

language C/C++ header file:

语言C / c++头文件:

//reflection.h
#pragma once
class Reflection {
public:
   extern "C" {
     static void exec(int& func_addr);
   }
}

language C++:

语言c++:

//mysourcefile.cpp
#pragma once
#include "reflection.h"
#include "map.h"

int main(){
   Map map;
   Reflection.exec(map.decode("run()"); // executes a function called run() in the current class
   wait(10);//seconds
   return 0;
}

void run(){
 cout<<"This is now running via reflection from an assembly procedure in a C function in a C++      function!";
}

output:

输出:

This is now running via reflection from an assembly procedure in a C function in a C++ function!

现在,它通过c++函数中的C函数中的程序集反射运行!