在运行时定义C++函数

3

我正在尝试调整我编写的数学代码,以允许任意函数,但我似乎只能在编译时预定义它们,这似乎很笨拙。我目前正在使用函数指针,但据我所知,使用functor也会出现同样的问题。为了提供一个简单的例子,对于前向差分求导,使用的代码如下:

double xsquared(double x) {
    return x*x;
}

double expx(double x) {
    return exp(x);
}

double forward(double x, double h, double (*af)(double)) {
    double answer = (af(x+h)-af(x))/h;

    return answer;  
}

在这里,第三个参数可以是前两个函数中的任意一个。然而,我想做的是传递用户输入(有效的C++代码),而不是事先设置函数。非常感谢您的帮助!


1
所以你想要构建一个完全功能的C++编译器?嗯...我认为这有点超出了Stack Overflow的范围。 - Jonathan Grynspan
C++ 不是一种脚本语言……你可以尝试与 Lua、Tcl 或 Python 等语言集成。 - Foo Bah
你正在使用错误的编程语言。(C++0x确实具有闭包等功能,但它可能仍然笨重。) - user395760
8个回答

5
历史上,您所请求的此类功能在C++中并不可用。通常的解决方法是嵌入一种非C++语言的解释器(例如Lua和Python专门设计为集成到C/C++应用程序中以允许脚本编写),或者创建一个特定于您的应用程序的新语言,具有您自己的解析器、编译器等。然而,情况正在改变。
Clang是一个由苹果开发的新型开源编译器,利用LLVM进行开发。Clang从头开始设计,旨在不仅作为编译器使用,还可以作为一个C++库嵌入到您的应用程序中。我自己没有尝试过,但您应该能够使用Clang做您想做的事情——将其链接为库,并要求它编译用户输入到应用程序中的代码。
您可以尝试查看ClamAV团队如何已经这样做了,以便可以用C编写新的病毒定义

至于其他编译器,我知道GCC最近增加了插件支持。可能可以利用这一点来连接GCC和您的应用程序,但由于GCC最初并不是为作为库而设计的,所以可能会更加困难。我不知道是否有其他具有类似功能的编译器。


LLVM支持JIT编译,这是关键特性。除了ClamAV之外,我知道还有一个编写CLang解释器的项目。虽然我记不得进展如何了 :) - Matthieu M.
@MatthieuM.:我认为你在考虑Cling - kirbyfan64sos
我确实是的 :) - Matthieu M.

3

由于C ++是一种完全编译语言,除非编写自己的编译器或解释器,否则您无法真正将用户输入转换为代码。但在本例中,可能可以为特定领域语言(DSL)构建一个简单的解释器,它将是数学公式。这一切取决于您想要做什么。


你现在可以用至少一个编译器来完成这个任务,参见我的答案。 - Joseph Garvin
明白了,谢谢。另一个用户向我推荐了muParser,这可能是我在最终代码中使用的工具,但我仍然有兴趣了解如何将自己的方程解释器的结果传递到函数中 - 有没有简要的解释? - Greg
@Greg 举个例子,您可以创建一个实现运算符() (函数调用) 的类,然后将调用委托给您的解释器,将从方程式分析中获得的抽象语法树传递给它。 - wendazhou

1
你可以将用户的输入通过编译器进行编译,然后执行生成的二进制文件。当然,这样做存在安全风险,因为他们可以执行任意代码。
更简单的方法是设计一种极简语言,让用户定义简单函数,并在C++中解析它们以执行正确的代码。

谢谢!我本来以为要写一个评论指出执行用户提供的C++代码是一个巨大的安全风险,但看来你已经注意到了。我非常高兴有人指出了这一点。 - Mac

1

最好的解决方案是使用像lua或python这样的嵌入式语言来完成这种类型的任务。请参见例如选择一个嵌入式语言以获取建议。


1

你可以使用小型C编译器作为库(libtcc)。

它允许你在运行时编译任意代码并加载它,但仅适用于C而不是C++。

通常的方法如下:

  • 将代码传递给编译器并创建共享对象或DLL
  • 加载此共享对象或DLL
  • 使用此共享对象中的函数。

0

虽然看起来像是一种放松,但有很多人已经为C++和C编写了方程解析器和解释器,其中许多是商业的,许多有缺陷,并且所有这些都像人群中的面孔一样不同。一个开始的地方是大学生编写中缀转后缀翻译器。其中一些系统使用括号分组,然后将项目放在堆栈上,就像您在旧的HP STL库中找到的那样。我花了30秒钟找到了这个:

http://www.speqmath.com/tutorials/expression_parser_cpp/index.html

可能的搜索字符串:"gcc '方程式解析器' 中缀转后缀"


0

C++不能像Perl等其他语言那样对自身进行运行时解释。

您唯一的选择是允许用户编译小型共享库,这些库可以在运行时由应用程序动态加载。


0

嗯,你可以做两件事情:

  1. 充分利用boost/C++0x lambda,在运行时定义函数。

  2. 如果只需要数学公式,像muParser这样的库被设计为将字符串转换为字节码,这可以被视为在运行时定义函数。


muParser看起来非常适合这项工作,谢谢。虽然如此,我认为我还是会尝试组合自己的基本方程解释器来帮助理解“幕后”的情况。 - Greg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接