雖然我對C++11沒有什麼興趣,因為C++03就已經有很多復雜的技術了。我曾經試圖把我學到的那些復雜的C++技術應用到項目中,但悲劇地發現這給團隊其他成員帶來了不小的負擔。其實也給未來一段時間的自己帶來了不小的負擔。尤其是template的應用,template代碼從外表上就一副唬人的樣子,就像即使你會Lisp,並且對Lisp中的括號不以為然,但看到滿屏幕的括號時依然內心不安。
但是稍微對C++11的一些特性做了解後,單從理論上來說,還是挺讓人有興趣的。我感覺C++11加入了不少函數式語言的特性和思想,這是我感興趣的最大理由。今天來看看C++11中的lambda。
C++03中,在使用STL容器時,或者我自己寫的類中,常有遍歷的需求,本來寫個functor傳進去就可以,但是這functor偏偏寫的很惡心。因為你需要局部定義一個結構體,重載operator(),並且,如果這個operator()依賴這個functor構建時的上下文信息,你得往這個結構體裡塞入若干成員,當然還得讓構造函數的參數變得越來越長。最後,在包含你這個functor使用以及結構體定義的這個代碼塊,在其代碼格式上就變得非常奇怪。如果你像我一樣常這樣應用,一定深有感觸。
然後,C++11來了,C++11中的lambda,就我個人而言,其語法還是非常現代的。來看看其文法形式(截自N2550):
lambda-expression:
lambda-introducer lambda-parameter-declaration compound-statement
lambda-introducer:
[ lambda-capture ]
lambda-capture:
capture-default
capture-list
capture-default , capture-list
capture-default:
&
=
capture-list:
capture
capture-list , capture
capture:
identifier
& identifier
this
lambda-parameter-declaration:
( lambda-parameter-declaration-list ) exception-specification lambda-return-type-clause
lambda-parameter-declaration-list:
lambda-parameter
lambda-parameter , lambda-parameter-declaration-list
lambda-parameter:
decl-specifier-seq declarator
lambda-return-type-clause:
-> type-id
翻譯過來大致就是這樣的形式:
[capture] (parameter) spec ->return-type { body }
capture就是這個lambda實現裡可以訪問的這個lambda定義時作用域裡的變量列表,就像Lua裡的upvalue。其實我覺得這個才是lambda最方便程序員的地方,一般的函數式語言其實不需要顯示聲明這個列表,直接引用這些變量即可。後面的部分都比較好理解,parameter就是這個lambda被調用時的形參列表,return-type就是這個lambda的返回值類型,body自然就是這個lambda的實現。至於spec,主要就是指定異常及body裡對capture裡的變量的使用權限。一個例子:
vector<int> ints;
ints.push_back(99);
ints.push_back(100);
ints.push_back(101);
int threhold = 100;
int sum = 0;
for_each(ints.begin(), ints.end(),
[threhold, &sum] (int v) {
if (v >= threhold) ++ sum;
});
printf("%d\n", sum);
capture使用了threhold和sum,但是threhold僅使用其值,而sum則使用了其引用,通過結果可以看出lambda中改變了sum的值。
C++11正在被越來越多的編譯器支持,也越來越支持得更好。這裡有個表,羅列了C++11的各個特性在各個編譯器上的支持情況,僅供查閱(以上示例代碼測試於vs2010,即MSVC10.0)。