使用C ++中的函数名称从字符串调用函数

如何从字符串中调用C ++函数?

而不是这样做,直接从字符串调用方法:

void callfunction(const char* callthis, int []params) { if (callthis == "callA") { callA(); } else if (callthis == "callB") { callB(params[0], params[1]); } else if (callthis == "callC") { callC(params[0]); } } 

在C#中我们使用typeof()然后从那里获取方法info和调用…我们可以在C ++中使用什么?

创建一个由字符串和函数指针组成的std :: map。 使用您要调用的所有函数创建地图。

还有其他方法可以做到这一点,涉及符号表和动态加载器,但这些方式不可移植或友好。

其他解决方案是同一主题的变体:

 switch (callthis) { case FUNCA: callA(); break; case FUNCB: callB(params); break; ... etc. } 

或搜索一组结构:

 struct { char *name; TFunc f; } funcdefs [] = { {"callA", callA}, {"callB", callB}, {"callC", callC}, ... etc. {NULL, NULL} }; for (int j = 0; funcdefs [j] .name; ++j) if (!strcmp (funcdefs [j] .name, callthis)) { funcdefs [j] .f (params); break; } 

您还可以查看如何向C ++应用程序添加reflection的答案? 有关RTTI的信息,C ++中的reflection机制。

祝好运。

替代方法:您可以使用函数指针数组并使用其索引调用所需的函数。

 typedef void (*TFunc)(int, int); TFunc arrptr[100]; void callFunction(int index, int params[]) { (*arrptr[index])(params[0], params[1]); } 

可能不是一个选项,但是如果你可以使用托管c ++(C ++ / CLI),你就可以像在C#中那样做。 这将需要.NET虽然……

没有好办法自动完成你的要求。 我会考虑两种不同的方式,具体取决于您认为需要调用的函数数量:

如果只有少数函数,请坚持使用您拥有的代码(请注意,如果您希望使用const char *,则无法将这些字符串与==运算符进行比较。您可以使用“strcmp()”,通过执行“#include ”)。

如果有很多函数,或者你经常在列表中添加和删除函数,那么你可能想要使用“std :: map”。 这会将函数名称字符串映射到函数指针。 我可能会将它包装在一个易于使用的类中:

 class Str2Fun { std::map data; public: void add( const char *funName, (void*)(int**) funPtr ); void call( const char *funName ); }; 

一般不可能

在纯标准C ++ 11中 ,如果要调用程序的任意可能函数(或者使用的库的任何可能函数),就不能真正实现该目标(从名称调用函数,在运行时通过某些任意字符串给出)。 it)从函数名称。 你可以确实嵌入一个解释器(例如Lua或GNU guile ),如xtofl的回答所示 。

保持从名称到function的关联

如果你知道一组可能可调用的函数,并且它们共享一个共同的签名(例如typedef int signature_T(int[]) ,你可能只使用从名称到函数的关联,例如某些std::map> ; BTW,C ++ 11的新function(闭包, std::functionauto ,lambdas)应该会有很多帮助。

在POSIX上使用动态链接工具,如dlsym

如果你把自己局限于像Linux这样的POSIX系统,你可以考虑其他一些技巧:使用dlsym(3)和dlopen(3)从一些未编码的名字中获取一个函数指针。 因此,您可以将要通过其名称调用的函数声明为extern "C" (禁用名称修改 ),您可以将程序与-rdynamic-ldl库链接。 您可以使用dlopen 动态加载 插件 – 或者通过dlopen -ing NULL获取主程序句柄 – 并使用dlsym从其名称中获取函数指针。 阅读C ++ dlopen mini howto和Drepper的如何编写共享库文章。

(Windows也有与dlsym几乎相同的function,因为它还有一个动态链接器 ;但我从未使用过Windows)

一些C ++框架库( Qt , POCO )以独立于操作系统的方式包装动态加载插件。

使用libffi调用任意函数

关于调用任意签名的函数存在问题。 在调用(或来自)C或C ++中的任何函数时,您绝对需要知道签名(至少在运行时,通常在编译时)(因为ABI规定了各种调用约定 )。 你可以使用libffi :

某些程序在编译时可能不知道要将哪些参数传递给函数。 例如,可以在运行时告诉解释器关于用于调用给定函数的参数的数量和类型。 Libffi可用于此类程序,以提供从解释程序到编译代码的桥梁。

即时生成机器代码

最后,您可以使用一些JIT库在运行时生成一些机器代码: GNU lightning , libjit , asmjit等简单的JIT库能够快速生成一些相当慢的机器代码,或者基于复杂编译器的JIT框架,如libgccjit或LLVM ,它们是生成优化的快速机器代码(但需要大量的生成时间,如编译器)。

在运行时生成C(或C ++代码),编译它并使它成为dlopen

一个相关的技巧只是在一个临时文件/tmp/foobar.c生成一些C或C ++代码,使用gcc -fPIC -O -shared /tmp/foobar.c -o /tmp/foobar.so将它编译成一个插件(所以请求与位置无关的代码 ) gcc -fPIC -O -shared /tmp/foobar.c -o /tmp/foobar.so ,然后使用dlopen动态加载该临时插件。 我在MELT中使用这种技巧(一种Lispy域特定语言来扩展和定制GCC ,可用的免费软件GPLv3)。 在实践中,编译器今天足够快,甚至允许交互式地使用这样的用户:用户可以在某些DSL中键入一个简单的表达式,基础设施正在将该DSL转换为C代码,然后将该代码编译成一个插件,该插件稍后是dlopen -编辑。 这在实践中对于交互式使用来说足够快(因为生成的C代码每个交互式表达式将具有几百行,并且编译只需要几分之一秒)。

其他编程语言

一些编程语言是homoiconic和/或具有一些eval工具,或启用多阶段编程 。 有些实现甚至能够在运行时生成非常高效的机器代码,特别是SBCL总是在每个表达式中转换为机器代码,即使在其read-eval-print循环中也是如此 。

您可以将函数声明包装成解释语言(如Lua或Perl或Python (boost有一些很好的框架) )。 然后使用该语言“按字符串”调用代码。

这些语言/包装器是为了做这些事情而构建的。 C ++不是,所以你会付出很多努力来增加对它的支持。