3

是的,我知道动态变量在 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 返回的代码停止产生正确的结果:我们不确定问题到底是什么,我们现在只是在探索其他途径. 新文件也很多比以前的更相似(由于其他工作),这是新技术的动机的一部分。如果我只需要几行代码以一种简单的方式协同工作,我希望我可以绕过代码生成。这不是“为我修好它!” 问题,我只想了解其他选项可能是什么。是的,我知道一开始情况并不好,如果从一开始就计划好了,就不会这样做。但这种设置可能是暂时的,正如我所说,它更像是一个概念证明而不是其他任何东西。

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

4

5 回答 5

1

变量本身实际上可以很容易地处理:读入值并将它们放入 a 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)。我猜大多数人都有自己的支持变量,因此您可能不需要编写自己的显式地图。

于 2012-06-30T04:01:35.193 回答
1

您可以尝试将各种函数组封装在匿名结构中,以实现类似于宏的“行为”但不是:

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");
...

If a user needs to change the code, he makes a copy of the struct, apply the changes, and redefines the macro:

struct
{
    ...changed code...
} MyStuff;

#define DoStuff MyStuff

These would be the only changes needed, if I understand your question correctly.

于 2012-07-06T07:03:01.627 回答
0

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

于 2012-06-30T03:56:30.013 回答
0

这可能只会引起更多的麻烦,但对于未来这样的事情,可能会考虑使用 boost.spirit 来构建一个实际的解析器,或者可能是 proto 来构建一种特定于域的语言。

于 2012-06-30T04:06:06.050 回答
0

(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 或任何其他脚本语言),这意味着您不必为每个模型重新编译,并且您也可以在运行时添加或删除实际的全局变量,但这更复杂。

于 2012-06-30T05:19:43.493 回答