如何通过exprtk的unknown_symbol_resolver创建向量类型变量?
如何通过exprtk的unknown_symbol_resolver创建向量类型变量?
嘿,我刚好碰到过类似的问题,exprtk确实没给symbol_table加直接创建向量的成员函数,但咱们可以在自定义的unknown_symbol_resolver里手动实现这个逻辑,其实不难!
核心思路就是:当解析器遇到未知符号(比如你例子里的foobar)时,我们在process方法里主动创建一个exprtk的向量对象,把它注册到符号表中,再告诉解析器这个符号已经处理完成。
先给你补全并优化一下你的代码,直接就能用:
#include <string> #include <stdio.h> #include <vector> #include "exprtk.hpp" using symbol_table_t = exprtk::symbol_table<double>; using parser_t = exprtk::parser<double>; using expression_t = exprtk::expression<double>; using vector_t = exprtk::vector<double>; template<typename T> struct myusr : public parser_t::unknown_symbol_resolver { using usr = typename parser_t::unknown_symbol_resolver; symbol_table_t& sym_table_; // 必须传入符号表的引用,这样才能把新创建的向量注册进去 myusr(symbol_table_t& st) : usr(usr::e_usrmode_extended), sym_table_(st) { } virtual bool process(const std::string& symbol, T& /* 这个参数对标量有用,向量用不上,所以忽略 */, parser_t::usrmode /* 模式参数,这里我们用默认的扩展模式 */, std::vector<std::string>& /* 额外符号列表,暂时不用 */) override { // 这里我默认把所有未知符号都创建成向量,你也可以加判断逻辑 // 比如只处理以"_vec"结尾的符号:if (symbol.ends_with("_vec")) { ... } vector_t* new_vec = new vector_t(); // 可以先设置向量初始大小,比如0,后续也可以动态调整 new_vec->resize(0); // 把向量注册到符号表,如果注册失败要释放内存 if (!sym_table_.add_vector(symbol, *new_vec)) { delete new_vec; return false; } // 返回true告诉解析器这个符号已经处理好了 return true; } // 析构函数里记得清理我们创建的向量,避免内存泄漏 virtual ~myusr() { const auto& vec_list = sym_table_.get_vector_list(); for (const auto& vec_pair : vec_list) { delete vec_pair.second; } } }; int main(int argc, char* argv[]) { if (argc < 2) { printf("用法:%s <表达式>\n", argv[0]); return 1; } std::string expr_str = argv[1]; symbol_table_t sym_table; expression_t expr; expr.register_symbol_table(sym_table); // 初始化我们的自定义解析器,传入符号表引用 myusr<double> resolver(sym_table); parser_t parser; // 告诉解析器启用我们的未知符号解析器 parser.enable_unknown_symbol_resolver(&resolver); // 编译表达式 if (!parser.compile(expr_str, expr)) { printf("编译错误:%s\n", parser.error().c_str()); return 1; } // 执行表达式并获取结果向量 vector_t result; expr.value(result); printf("结果向量大小:%zu\n", result.size()); for (std::size_t i = 0; i < result.size(); ++i) { printf("result[%zu] = %.2f\n", i, result[i]); } return 0; }
这里有几个要注意的地方:
- 自定义的
myusr必须持有符号表的引用,不然没法把新创建的向量注册进去 - 记得在析构函数里清理动态创建的向量,不然会有内存泄漏
- 你可以根据自己的需求修改
process方法里的逻辑,比如只把特定命名规则的符号创建成向量,而不是所有未知符号
比如你测试的时候运行./a.out "return [foobar];",解析器遇到foobar这个未知符号,就会自动创建一个向量,然后表达式会返回这个向量,程序就能正常输出结果啦。
备注:内容来源于stack exchange,提问作者Eric Johnson
相关产品推荐
相关产品推荐

