TinyLambda


晚上突发奇想,想用C++实现一个无比简陋的lambda:只能作为匿名函数,不带闭包,无捕获,所有中间值和结果都是int,利用C++98实现。

这类lambda实际上就是Eigen这类库中延迟计算的一个原型,写起来并不复杂,大约100行左右代码就能完成。

测试例子:

分析

我们最终要实现的一个东西,我们希望它具有的特性是:

  • 具有int operator() (const int, const int),能当作函数使用
  • 能在+<运算符下和整数和自身的类运算,产生一个新的这类对象

之前我们分析过:对于这类抽象,如果需要运行时多态,就应该使用继承与虚函数;如果不需要,就应该使用静态多态

动态多态

先尝试一下动态多态的思想:

定义接口:

对于+,返回一个继承自lambda_interface的子类:

这里需要注意的是clone,众所周知构造函数不能是虚函数,但是复制构造可以利用clone()来变相实现虚函数的效果。

定义两个placeholder,它们始终返回第1/2个参数:

对于常数,我们构造一个constant类把它包裹起来:

测试:

迄今为止,我们已经实现了动态多态的+,我们发现,这一实现存在着诸多不足:

  • +中的常数暂时还不能自动转换成constant类型,需要手动包裹。之后的改进手段就是重载+(const lambda_interface&, const int)
  • 较为丑陋,这其中所有信息都可以编译时获得,引入了虚函数增加了大量不必要的负担,并且中间堆上分配了不少内存,容易造成性能问题。

静态多态

静态多态不利用语法上的继承来实现is_a的特性描述,而是利用模板+各个类相同的接口来实现一种语法在不同类上不同的表现。

例如:

这样就实现了语义上的多态性。

实现:

这个不是接口,而是为了减少代码量而把共同部分抽出来了而已:

因为一个运算符其两个操作数的类型没有统一的接口,所以利用模板来生成基类。

+类:

+函数也要利用模板来生成,注意:这里把int替换成了constant类:

replace<T>::type如果T不是int,返回自身,否则返回constant

constantplaceholder:

静态多态版本完成(上面省略了<>,和+一样处理就行了

总结

以上全部代码的完整版都能在:https://github.com/htfy96/CppToys/tree/master/lambdatest 看到

静态多态在不需要运行时信息时,不仅降低了overhead,而且给程序编写带来了很大的简洁。在这种模式下,C++中的类型可以当作duck typing的方式来使用,从而给了程序员很大的自由。 不过,缺点也在于弱类型约束一旦出现bug很有可能会产生大量无用报错信息,缓解这一缺点可以使用SFINAE,或是进入C++11年代的static_assert(你都有了C++11了手写什么lambda),或是未来C++17的concept

总之,C++不强迫程序员选择什么,这就是为什么我非常喜欢这门语言。

Self-promotion

SJTU大二本科生,寻求暑假实习中。偏向于后端,有利用Golang+redis开发的经历。

Linkedin:http://cn.linkedin.com/in/vicluo