看看之前做到哪里了:实现了一个赋值的lambda表达式。
这次来看看怎么添加新的运算进去,然后再说点关于表达式的问题,为以后的扩展打下理论基础。
先看看之前的代码吧,
1 template <typename _U>
2 struct op
3 {
4 op(_U i)
5 : _i(i)
6 {}
7
8 _U _i;
9
10 template<typename _T>
11 _T& operator()(_T& i)
12 {
13 i = _i;
14 }
15 };
16
17 struct place_holder
18 {
19 template <typename _T>
20 op<_T> operator=(_T i)
21 {
22 return op<_T>(i)
23 }
24 };
25
26 place_holder _1;
27
28 vector<double> v;
29 for_each(v.begin(), v.end(), _1 = 3);
现在,要在这个基础上,添加新的操作进来,比如说operator+=吧。要怎么做呢?
1. place_holder要重载operator+= 才可以,因为place_holder的主要任务就是替我们生成一个仿函数。
2. 要有相应的仿函数来真正的做 += ,也就是说在仿函数的operator()里面,要有真正干活的操作。
好了,开始吧, 先看看实现,然后在解释。
1 struct op
2 {
3 op(int i)
4 : _i(i)
5 {}
6
7 int _i;
8
9 int operator()(int& i)
10 {
11 return i = _i;
12 }
13 };
14
15 struct op1
16 {
17 op1(int i)
18 : _i(i)
19 {}
20
21 int _i;
22
23 int operator()(int& i)
24 {
25 return i += _i;
26 }
27 };
28
29 struct place_holder
30 {
31 op operator=(int i)
32 {
33 return op(i);
34 }
35
36 op1 operator+=(int i)
37 {
38 return op1(i);
39 }
40 };
41
42 place_holder _1;
43
44 void main()
45 {
46
47 vector<int> v;
48 v.push_back(12);
49 v.push_back(1342);
50 v.push_back(23);
51
52 for_each(v.begin(), v.end(), _1 += 3);
53 }
好了,现在+=操作已经被支持了。多么简单呀。来看看都做了些什么:
1. 给place_holder增加了一个operator+=函数, operator+= 返回op1类型的仿函数。
2. 增加了一个op1的仿函数(类模板),用来真正的执行 += 的运算。
当编译器看到 _1 += 3 时,去找到 place_holder::operator+=, 然后把模板参数推导成 int,返回一个 op1<int> 对象。
在for_each里面,就调用op1<int>::operator+=了。
当然也可以这么用:
1 double x = 0.0;
2 (_1 += 10.4)(x);
到这里大家想必已经可以照猫画虎,实现其他操作了吧。但是当实现的操作多起来的时候,新的问题就来了,比如想要个 _1 = _2 + 3.0 的时候呢?看看下面的代码:
1 _1 = _2 + 3.0 //lambda表达式
2
3 void fun(double& lhs, const double& rhs) //相同功能函数
4 {
5 lhs = rhs + 3.0;
6 }
7
8 struct op
9 {
10 template <typename _T>
11 _T operator(_T& lhs, const _T& rhs)
12 {
13 lhs = rhs + 3.0;
14 }
15 };
16
看看lambda表达式为我们省了多少代码!当然我不是为了说这个而写这么长段代码,我想说,那个op是我们的最终目标,能实现吗?不能!因为在op里面直接出现了3.0,按照前面的惯例,应该在op里面有一个成员变量来保存3.0,不是吗?根本问题不在这里。
仔细想想我们到底在做什么,
我们在用template的技法,“编译”表达式。
place_holder其实就像C++的表达式,op就像汇编语言,通过template技法,把place_holder的表达式“编译”成用op组成的操作,op是可以直接被C++运行的仿函数。也就是说是一个从lambda语法到C++语法的编译器,但是这个编译器靠template技法实现,由真正的C++编译器进行模板推导,最后“编译”成C++的仿函数。所以一句话就是:
用template技法实现的从lambda语法到C++语法的“编译器”。
所以根本问题在于op的这种写法没有办法扩展,难道对于每种连起来的操作,都分别写一个op吗(比如_1 = (_2 + 3.0) * (_2 - 3.0),C++中表达式无数,要是每种都要写个op,那要lambda何用 )?op相当于汇编,只要几个简单的运算就OK,关键在于按照place_holder的表达,把op组合起来。
下一篇准备介绍一下boost::tuple,和表达式编译,因为它们是实现lambda的关键武器。
posted on 2009-02-22 22:11
尹东斐 阅读(1758)
评论(1) 编辑 收藏 引用 所属分类:
深入探索 boost::lambda 系列