初窺c++11:lambda函式及其用法

峻峰飛陽發表於2015-06-14
為什麼需要lambda函式
匿名函式是許多程式語言都支援的概念,有函式體,沒有函式名。1958年,lisp首先採用匿名函式,匿名函式最常用的是作為回撥函式的值。正因為有這樣的需求,c++引入了lambda 函式,你可以在你的原始碼中內聯一個lambda函式,這就使得建立快速的,一次性的函式變得簡單了。例如,你可以把lambda函式可在引數中傳遞給std::sort函式

#include <algorithm>
#include <cmath>
void abssort(float* x, unsigned N) {
    std::sort(x, x + N,
        // Lambda expression begins
        [](float a, float b) {
            return std::abs(a) < std::abs(b);
        });
}
你可能會問,使用函式物件不是也可以嗎?是的,函式物件當然沒問題,自己寫的回撥函式,你可以傳個函式指標也沒有問題。他們有優點也有缺點。函式物件能維護狀態,但語法開銷大,而函式指標語法開銷小,卻沒法儲存範圍內的狀態。如果你覺得魚和熊掌不可兼得,那你可錯了。lambda函式結合了兩者的優點,讓你寫出優雅簡潔的程式碼。

基本lambda語法
基本形式如下:
[capture](parameters)->return-type {body}

[]叫做捕獲說明符,表示一個lambda表示式的開始。接下來是引數列表,即這個匿名的lambda函式的引數,->return-type表示返回型別,如果沒有返回型別,則可以省略這部分。想知道為什麼返回型別可以這麼表示,這涉及到c++11的另一特性,參見自動型別推導,最後就是函式體部分了。
我們可以這樣輸出"hello,world"
auto func = [] () { cout << "hello,world"; };
func(); // now call the function

變數捕獲與lambda閉包實現
string name;
cin >> name;
[&](){cout << name;}();

lambda函式能夠捕獲lambda函式外的具有自動儲存時期的變數。函式體與這些變數的集合合起來叫閉包。
  • [] 不擷取任何變數
  • [&} 擷取外部作用域中所有變數,並作為引用在函式體中使用
  • [=] 擷取外部作用域中所有變數,並拷貝一份在函式體中使用
  • [=, &foo] 擷取外部作用域中所有變數,並拷貝一份在函式體中使用,但是對foo變數使用引用
  • [bar] 擷取bar變數並且拷貝一份在函式體重使用,同時不擷取其他變數
  • [x, &y] x按值傳遞,y按引用傳遞
  • [this] 擷取當前類中的this指標。如果已經使用了&或者=就預設新增此選項。
看到這,不禁要問,這魔法般的變數捕獲是怎麼實現的呢?原來,lambda是通過建立個小類來實現的。這個類過載了操作符(),一個lambda函式是該類的一個例項。當該類被構造時,周圍的變數就傳遞給建構函式並以成員變數儲存起來。看起來跟函式物件很相似。

最後,lambda函式的型別是什麼呢,答案是std:function。

相關文章