看看之前做到哪里了:實現了一個賦值的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
尹東斐 閱讀(1767)
評論(1) 編輯 收藏 引用 所屬分類:
深入探索 boost::lambda 系列