继前几天写了个程序化打表的网页小工具之后,一方面我觉得手动输入表达式太麻烦了,可以用下拉列表来组合表达式,另一方面就是不使用字符串转函数,而是用lambda来组合创建出新的函数,这种方法适用于所有可以创建函数对象的编程语言。
基本原理
主要的流程就是递归的解析表达式,如果当前解析出来的是一个函数,那就依次解析它的每个参数,每个参数解析出来也会是一个函数对象,递归的终止条件为不需要参数的函数。
我也还没有深入研究如何引入参数,所以返回的全是无参的函数,传递参数的方法是通过类似getX()
这样的函数来获取外部参数,同时也作为递归的终止条件。
代码实现
因为纯C++的人机交互方式其实挺少的,所以还是用字符串来举例子,先写一个很简陋的parser
,能够将一个字符串解析为函数名和各个参数的表达式,第0个元素为函数名,后续依次为各个参数字符串。
1 | vector<string>parser(string str){ |
字符串处理的函数写起来就是这么麻烦,这个不是重点,就不过多解释了,下面才是主要的代码
1 | int x=0,y=1; |
上面的例子中,analysis
将一个表达式字符串解析为一个函数,对于嵌套的函数则对其每个参数递归的解析为函数,再将函数调用作为上一层函数的参数,例如f(g(x,y))
,先解析出函数名f,再对它的参数字符串g(x,y)
调用analysis
,函数g有两个参数,先对x调用analysis
,达到终止条件,返回getx
,同理y返回gety
,这时候g的参数全部解析出来了,返回一个函数对象,即g(getx(),gety())
,作为f的参数,最终返回的函数效果上等价于
1 | auto foo(){return f(g(getx(),gety()));} |
最后可以写个main来试试
1 | int main(){ |
不出意外上面的运行结果会是2。
最后
运行效率上,因为套了很多层lambda,运行效率肯定会慢,或许也像是某种jit(即时编译),只能说是一个很有趣的玩具。后续应该可以有两种改进,一种是用数组传参,然后把所有函数都放在一个map里,做一个通用化的组合。另一种是用class把变量包装起来,然后再加上模板或许可以做出像真正的函数一样传参调用函数对象(现在的这种形式不能传参,等价的方法是在外部修改x和y)