创建动态变量



是的,我知道动态变量在 c++ 中是不可能的。我正在寻找的是一种解决方法。

这个想法基本上是这样的。我有一堆数学模型。它们都具有完全相同的形式,除了

  1. 几个函数的数学定义
  2. 所需的常量:它们的名称、数量和值。

常量的值可能会在实验之间发生变化,但其他一切都是材料模型本身的属性。模型的常量参数在输入文件中以以下形式给出

variable_A=2.0

材料模型(包括所有函数)以前是通过生成的代码创建的,通过 Maple 从抽象的数学表达式生成,并具有很好的 GUI 环境。由于多种原因,现在可悲的是,这种情况被打破了。由于其他一些工作,这些模型现在在代码中都完全相同,除了它们在形式描述上有所不同。我正在寻找一个更简单的替代方案,而不是有一个完整的独立程序来生成此代码(目前已损坏,我们过去拥有的程序),因为现在我只需要在整个给定文件中大约 20 行即可将一种材料与另一种材料区分开来。但是,实现这些模型的用户不需要了解 c++。因此,虽然我可以简单地要求他们浏览文件并在不同的地方更改内容,但我正在寻找更用户友好的东西:因此用户可以在一个地方更改几行并以这种方式定义他们的模型,而无需查看其余代码。

用户要定义的函数如下所示。

double myfunction(double arg1, double arg2, vector arg3 ) \just an example
{
    ...
    ...
    double a=database.find_constant("a_const");
    double b=database.find_constant("b_const");
    return sqrt(a*3+pow(b,2)-a/b)+...; \still example pseudocode
}

顶部的省略号相当丑陋(不是坏代码,只是语法繁重且无关紧要),所以我不希望最终用户必须处理它们。我的问题可能可以通过示例更好地描述:

我最初的计划是在顶部使用宏(是的,我知道,恐怖),这样它就可以变成类似的东西

 #define A database.find_constant("a_const")
 #define FUNCTION pow(A-2,3)   
 ...
double myfunction(...)
{
    ...
    return FUNCTION;
}

但后来我发现你不能嵌套宏。回想起来,这是显而易见的,但我跑题了。然后我意识到我可以更改#define A语句,使A成为全局变量。然后我甚至因为考虑全局变量而自责。基本上,我所有试图把这些都放在一个用户不需要太多 c++ 知识的地方是荒谬和/或非常不安全的。

通常我讨厌问这种开放式的问题,但我真的不想让自己头疼。我只会在这个项目上工作很短的时间,所以设计某种形式的 UI 和/或生成代码是不切实际的。我现在要进行"概念验证"。

有没有比让他们通过模型并直接更改函数中所需的行更好的方法?

编辑:我没有写整个项目,也不是最初打算以这种方式工作。我们用于生成这些文件的原始工具使用了 Maple 的代码生成,其中函数和变量作为 Maple 语法输入到一个漂亮的 GUI 中。不幸的是,GUI 似乎不再(始终如一地)工作,一旦我们切换版本,Maple 返回的代码就停止产生正确的结果:我们不确定问题到底是什么,我们现在只是在探索其他途径。新文件也比以前的文件更相似(由于其他工作),这是新技术动机的一部分。我希望如果我只需要几行以简单的方式协同工作,我就可以绕过代码生成。这不是"为我修复它! 问题,我只是想了解一下其他选择可能是什么。是的,我知道这不是一个好情况,如果从一开始就计划好,就不会这样做。但这种设置可能是暂时的,正如我所说,它更像是一个概念证明,而不是其他任何东西。

希望这个问题现在更清楚了。我的问题特别在于以简单易用的方式将所有内容分组到一个地方。感谢您的耐心等待。

您可以尝试"行为"类似于宏但不是,方法是将各种函数组封装在匿名结构中:

struct
{
    double find_constant(const char* s) { do-stuff...; }
    double calc_value(int a, int b) { do-stuff...; }
    ...
} GeneralStuff;

使用宏访问此结构中的函数:

#define DoStuff GeneralStuff

并在您的代码中访问它:

...
DoStuff.find_constant("a_const");
...

如果用户需要更改代码,他会复制结构,应用更改,然后重新定义宏:

struct
{
    ...changed code...
} MyStuff;
#define DoStuff MyStuff

如果我正确理解您的问题,这些将是唯一需要的更改。

变量

本身实际上可以很容易地处理:读取值并将它们放入std::map<std::string, double>中(或者,如果值都是整数,则int而不是double)。例如:

std::map<std::string, double> values;
// Code to read name and value from the file goes here.
// Then something like:
values[name] = value;

其余的——评估表情,是一个相当深层次的主题。不过,它的代码很容易找到(例如,muParser)。我猜大多数人都有自己的支持变量,所以你可能不需要编写自己的显式映射。

你需要的

只是让他们在输入文件中编写表达式,然后自己解析它并从数据库中查找任何未知的引用,然后评估它。如果您不需要非常高的评估性能,这对您和他们来说都相对简单。例如,您可以使用Lua非常轻松地自然地执行此操作 - 您所要做的就是在全局表上设置__index元表值以查找数据库,瞧-所有数据库常量都是"全局"Lua值。

这可能只会引起更多的麻烦,但对于未来这样的东西,也许可以考虑使用 boost.spirit 来构建一个实际的解析器,或者可能是原型来构建一个特定于领域的语言。

(1)如果您希望用户查看和编辑最少的代码,则可以考虑滥用预处理器,方法是将代码拆分为数学之前的位(BEGIN_ROBERTS_MAGIC.inl)和数学之后的代码(END_ROBERTS_MAGIC.inl)

BEGIN_ROBERTS_MAGIC.inl(您的代码)

#include <cmath>
...otherstuff
double function(*args go here*)
{
    ....prep work
    //this file ends right before the lines with the math

END_ROBERTS_MAGIC.inl(您的代码)

    //this file begins right after the lines with the math
}
...otherstuff

STUPID_PHYSICS_MODEL.cpp(他们的代码)

#include "BEGIN_ROBERTS_MAGIC.inl"
double a=database.find_constant("a_const"); //or double a = constant["a"];
double b=database.find_constant("b_const"); //or double b = constant["b"];
return sqrt(a*3+pow(b,2)-a/b)+...;
#include "END_ROBERTS_MAGIC.inl

这意味着其他人看到的文件只有五行左右的代码,看起来非常简单,一点也不吓人,所有的魔力都隐藏在他们看不到的其他文件中。

(2)正如其他人所建议的,您可以将用户的代码放入不属于C++代码的脚本中(通过spirit,lua,javascript或任何其他脚本语言),这意味着您必须为每个模型重新编译,并且您还可以在运行时添加或删除实际的全局变量,但这更复杂。

相关内容

  • 没有找到相关文章

最新更新