【问题标题】:Is there any kind of "expression class" (C++)是否有任何类型的“表达式类”(C++)
【发布时间】:2009-06-10 21:27:39
【问题描述】:

我正在创建一个游戏,让玩家输入输入,改变一些状态,然后检查“目标值”是否为真(显然这个描述被大大简化了),我希望能够让那个目标值成为从玩家生命低于某个值到剩余敌人数量为零。是否有任何“表达式类”可以保存一个简单的“value1 比较运算符 value2”并检查它?即:

expression goal(x = 4);

如果没有,有人对我如何开发表达式类有任何建议吗?

编辑:另一个(更接近我想要实现的目标)示例:

game.init(){ expression goal = FileRead(goalfile); }
game.checkstate(){ if(goal) exit(1); } //exit 1 is the games win state

//another more specific eg.:
class level1 { public: expression goal(total_enemies == 0); };
class level2 { public: expression goal(player.x == goal.x && player.y == goal.y); };

【问题讨论】:

    标签: c++ expression


    【解决方案1】:

    动态表达式

    如果您想从用户那里接收一个字符串并从中构建一个表达式,那么C++ Mathematical Expression Library 可能适合您的要求?

    template<typename T>
    void trig_function()
    {
       std::string expression_string = "clamp(-1.0,sin(2 * pi * x) + cos(x / 2 * pi),+1.0)";
       T x;
       exprtk::symbol_table<T> symbol_table;
       symbol_table.add_variable("x",x);
       symbol_table.add_constants();
    
       exprtk::expression<T> expression;
       expression.register_symbol_table(symbol_table);
    
       exprtk::parser<T> parser;
       parser.compile(expression_string,expression);
    
       for (x = T(-5.0); x <= T(+5.0); x += 0.001)
       {
          T y = expression.value();
          printf("%19.15f\t%19.15f\n",x,y);
       }
    }
    

    还可以嵌入脚本语言,例如LuaPython,这将为您(甚至)提供更多功能。如果您正在编写游戏,则需要考虑这一点,因为您可能需要编写大部分游戏的脚本。

    如果您使用的是Qt,您可以使用QtScript(Javascript-ish)来运行从您的 QObject 派生对象中读取(静态或动态)属性的表达式。

    使用上述其中一个可以让您不必编写自己的解析器、AST 和求值器,但是对于一小部分运算符,如果您使用 Boost.Spirit 或其他一些不错的东西,应该不会太难拼凑一些东西解析库。

    静态表达式

    为了在一组预定义的表达式(即在编译时已知)之间进行选择,您应该将表达式存储在多态函数对象中。

    对于 C++11,如果您可以使用,请使用 std::function 和 lambda 表达式。

    std::function<bool (int, int)> expr = [](int a, int b) { a*2 < b };
    

    对于早期的编译器,我建议使用 Boost (boost::) 或 C++0x TR1 (std::) 中的函数和绑定,具体取决于您的编译器。此外,Boost.Lambda 在这里会有所帮助,因为它允许您构造和存储表达式以供以后评估。但是,如果您不熟悉 C++ 和模板(或函数式编程),可能会吓到您。

    你可以这样写

    using namespace boost::lambda;
    boost::function<bool (int, int)> myexpr1 = (_1 + _2) > 20;
    boost::function<bool (int, int)> myexpr2 = (_1 * _2) > 42;
    std::cout << myexpr1(4,7) << " " << myexpr2(2,5);
    

    使用绑定,它看起来像:

    boost::function<bool (Player&)> check = bind(&Player::getHealth, _1) > 20;
    Player p1;
    if (check(p1)) { dostuff(); }
    
    check = bind(&Player::getGold, _1) < 42;
    if (check(p1)) { doOtherStuff(); }
    

    【讨论】:

    • 不幸的是,这对于任意表达式是完全不切实际的。我认为这是海报真正想要的(尽管他的例子是“val1 op val2”)。
    • 是吗?使用 boost::lambda 你可以组合各种表达式,甚至语句等等。什么意思?
    • 好吧,因为 boost lambdas 是在编译时构造的,并且只由调用者使用。如果用户输入了您没有考虑的操作组合,您会怎么做。由于数学运算的组合数不胜数……当然,您不能静态地考虑所有这些。
    • 啊..我没有看到OP想要动态构造表达式。这有点不清楚。我会编辑我的帖子。
    【解决方案2】:

    没有在运行时编译表达式的标准方法。您必须以其他方式进行。

    您可以考虑使用脚本语言,如 Lua 或 Python,并将其嵌入到您的 C++ 中。这将使您的玩家能够按照您希望的程度进行编程。

    【讨论】:

    • +1 推荐 Lua。 Lua 作为游戏和移动设备的轻量级嵌入式引擎,几乎无处不在。
    【解决方案3】:

    不,没有那样的东西。也许表达式类有点太抽象了。用 IsReached() 方法定义各种目标类怎么样?

    【讨论】:

      【解决方案4】:

      C++ 没有将此作为语言的一部分——在运行时无法访问解析程序的相同内容。

      不过,我确信您可以使用许多第三方算术解析器库。

      【讨论】:

      • 我认为他不是这个意思。
      【解决方案5】:

      我认为您可以定义自己的类并使用“assert”关键字解决问题,但我可能理解错误。

      http://www.cplusplus.com/reference/clibrary/cassert/assert/

      【讨论】:

        【解决方案6】:

        为什么不构建自己的表达式类?

        class GoalBase
        {
            virtual bool goal() = 0;
        };
        
        class Enemies : public GoalBase 
        {
           // ..
           private:
              int enemies_;
        
           public:
              Enemies(int start) : enemies_(start) {}
              void kill() { if (enemies_) --enemies_; }
              bool goal() { return enemies_ == 0; }
        };
        
        int main()
        {
            Enemies enemiesToKill(5);
            enemiesToKill.kill();    
        
            // ..
            if (enemiesToKill.goal()) {
                // ..
            }
        
            return 0;
        }
        

        其他类可能有其他方法、参数、运算符等。发挥你的想象力。

        【讨论】:

          【解决方案7】:

          在 C++ 中没有标准的方法。一种解决方案是编写自己的解析器。

          我推荐的另一种解决方案:在您的程序中嵌入一个 Lua 解释器。 Lua 是一种简单但功能强大的编程语言,它还具有极其轻量级 (http://www.ibm.com/developerworks/linux/library/l-embed-lua/index.html

          在游戏中嵌入 Lua 有许多不错的附带优势:

          • 您可以将其用作强大的 游戏的配置语言
          • 有了 Lua,你 可以轻松创建命令行 交互环境,即 非常适合测试和实验。例如,您将 能够改变游戏引擎 参数看看效果 立即,无需重新编译。这对于“研究”项目或游戏编程特别方便。

          【讨论】:

            【解决方案8】:

            静态表达式

            (修改Macke的帖子)

            当您的表达式在编译时已知时,您可以使用std::function。但是,性能可能不是最佳的。

            您可以使用 C++11 模板和宏在编译时自动注册测试并在运行时以(推测)最小的运行时开销执行它们。可以在here 找到概念验证实现。

            从长远来看,名为“Contracts”的语言功能可以完成这项工作。 (N4415, N4435, N4378) 如今,有各种库可用于支持合约编程。

            【讨论】:

              【解决方案9】:

              似乎没有那么多公认的 C++ 表达式评估库。我为 CSVfix 编写了自己的代码,您可以通过查看构成 CSVfix 源的一部分的 ALib 库中的 a_expr.ha_expr.cpp 文件来理解。评估者没有太多可以推荐自己的东西,除了它完成了这项工作并且(恕我直言)相当容易理解。

              不幸的是,目前没有针对评估者的公开文档,而且根据我自己的经验法则,没有记录的内容不能重复使用。但是,单元测试显示了它是如何使用的,如果你有兴趣,源代码可能会给你一些关于实现你自己的评估器的想法。

              【讨论】:

                猜你喜欢
                • 2013-04-23
                • 1970-01-01
                • 2021-08-16
                • 2023-03-26
                • 1970-01-01
                • 2018-04-25
                • 2021-07-28
                • 1970-01-01
                相关资源
                最近更新 更多