c++11新特性匿名函數(shù)

c++ lambda表達(dá)式詳解

轉(zhuǎn)載請注明:http://krystism.is-programmer.com/若有錯誤,請多多指正,謝謝!
  lambda表達(dá)式是c++11標(biāo)準(zhǔn)新加特性,學(xué)過python的一定不會陌生了,或者類似javascript的閉包。cppreference中的定義是:--*Constructs a closure: an unnamed function object capable of capturing variables in scope. *—-簡單地說就是定義一個臨時局部匿名函數(shù)。語法為:
[ capture ] ( params ) mutable exception attribute -> ret { body }
其中capture為定義外部變量是否可見(捕獲),(這里的外部變量是指與定義這個lambda處于同一個作用域的變量)。
若為空,則表示不捕獲所有外部變量,即所有外部變量均不可訪問,= 表示所有外部變量均以值的形式捕獲,在body中訪問外部變量時,訪問的是外部變量的一個副本,類似函數(shù)的值傳遞,因此在body中對外部變量的修改均不影響外部變量原來的值。& 表示以引用的形式捕獲,后面加上需要捕獲的變量名,沒有變量名,則表示以引用形式捕獲所有變量,類似函數(shù)的引用傳遞,body操作的是外部變量的引用,因此body中修改外部變量的值會影響原來的值。例如:[ ]表示不捕獲任何外部變量, [a, b]以值的形式捕獲a,b, [=]以值的形式捕獲所有外部變量,[&a, b]a以引用的形式捕獲,而b以值的形式捕獲,[&, a],除了a以值的形似捕獲,其他均以引用的形式捕獲,[this]以值的形式捕獲this指針!


params就是函數(shù)的形參,和普通函數(shù)類似,不過若沒有形參,這個部分可以省略。
mutalbe表示運(yùn)行body修改通過拷貝捕獲的參數(shù),exception聲明可能拋出的異常,attribute 修飾符,參考:http://en.cppreference.com/w/cpp/language/attributes 。->ret ret表示返回類型,如果能夠根據(jù)返回語句自動推導(dǎo),則可以省略,body即函數(shù)體。
注意:除了capture和body是必需的,其他均可以省略,即

int int main(int argc, char const *argv[])
{
    []() {};
    return 0;
}

定義了一個空lambda表達(dá)式,并執(zhí)行(實(shí)際上它什么都沒有做)。

int main(int argc, char **argv)
{
    int i = 0;
    []{cout << i << endl;}(); /* 'i' is not captured */
}

聲明這段代碼不能編譯通過,因?yàn)閇 ] 沒有捕獲任何外部變量,因此i是不可見的,lambda不能訪問i。

int main(int argc, char **argv)
{
    int i = 0;
    cout << i << endl;
    [=]()mutable{cout << ++i << endl;}();
    cout << i << endl;

上面的代碼輸出為0, 1, 0,注意mutable是必需的,因?yàn)閎ody中修改了捕獲的i,由于i是以值傳遞的,因此并沒有修改i原來的值,而是i的一個副本。

int main(int argc, char **argv)
{
    int i = 0;
    cout << i << endl;
    [&](){cout << ++i << endl;}();
    cout << i << endl;

上面代碼輸出0, 1, 1,因?yàn)閕是以引用傳遞的,而body中修改了i的值。
lambda表達(dá)式有什么用呢? lambda的作用就是創(chuàng)建一個臨時匿名函數(shù),想想有STL算法中很多需要傳遞謂詞函數(shù),比如count_if。假如我有一個字符串容器,我需要統(tǒng)計(jì)長度大于3的個數(shù),則可以這樣:

int main(int argc, char **argv)
{
    vector<string> s = {"1", "12", "123", "1234", "12345", "123456", "1234567"};
    cout << count_if(begin(s), end(s), [](string s){return s.size() > 3;});
  }

這樣就不必要再聲明一個函數(shù)了,代碼比較簡潔。
還有一個問題就是,我可能需要統(tǒng)計(jì)字符串長度大于4,或者5,或者6,顯然不能通過傳遞一個形參來實(shí)現(xiàn),因?yàn)橹^詞函數(shù)限定只能傳遞一個形參,這里我們傳遞的是string,而不能再傳遞一個表示長度的數(shù)。 如果定義全局函數(shù)實(shí)現(xiàn),則我們有兩種方式:
一是聲明一個全局變量,通過和這個全局變量作比較。二是分別聲明大于4或者5的函數(shù)。顯然兩個辦法都不太好。全局變量污染一直是很危險(xiǎn)的,而聲明多個函數(shù)顯然不科學(xué),如果有更多的需求,則需聲明gt2, gt3, gt4 ...。 這個用lambda表達(dá)式似乎更好,如:

int main(int argc, char **argv)
{
    vector<string> s = {"1", "12", "123", "1234", "12345", "123456", "1234567"};
    string::size_type n = 3;
    cout << count_if(begin(s), end(s), [n](string s){return s.size() > n;});
} 

注意這里的n并不是全局變量,所以不存在全局變量污染的問題。當(dāng)然還有更好的辦法,那就是利用函數(shù)對象,如:

using namespace std;
class Gt
{
    public:
        typedef string::size_type size_type;
        Gt(size_type i):n(i){};
        Gt():n(0){};
        void setN(const size_type& i) {
            n = i;
        }
        size_type getN() const{return n;}
        bool operator () (const string &s) const {return s.size() > n;}
        operator int() const { return n;}
    private:
        string::size_type n = 0;
};
inline Gt operator + (const Gt &s1, const Gt &s2)
{
    return Gt(s1.getN() + s2.getN());
}
int main(int argc, char **argv)
{
    vector<string> s = {"1", "12", "123", "1234", "12345", "123456", "1234567"};
    cout << count_if(begin(s), end(s), Gt(1)) << endl; /* > 1 */
    cout << count_if(begin(s), end(s), Gt(2)) << endl; /* > 2 */
    cout << count_if(begin(s), end(s), Gt(2) + Gt(3)) << endl; /* > 5 */
    return 0;
}

上面分別統(tǒng)計(jì)長度大于1,大于2,大于5的字符串?dāng)?shù)量(重載+運(yùn)算符,純屬娛樂?。?。
lambda表達(dá)式另外一個功能是聲明局部函數(shù)。我們知道c++中是不允許在函數(shù)中嵌套定義函數(shù)的,如果要聲明一個局部函數(shù),即只能在函數(shù)內(nèi)部調(diào)用,則可以用lambda實(shí)現(xiàn),如聲明一個min函數(shù),返回a,b中較小值。則

#include <iostream>
using namespace std;
int main(int argc, char **argv)
{
    auto min = [](int a, int b) -> int{
        return a < b ? a : b;
    };
    cout << min(1, 2) << endl;
    cout << min(8, 2) << endl;
    return 0;
}```
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容