C++11新特性--lambda

匿名函數(shù)--lambda函數(shù)

????匿名函數(shù)或者匿名類這種語法在其他語言(如lisp,java中)早有應(yīng)用。在C++11中正式引入了lambda函數(shù),在很多場(chǎng)景下讓程序變得更加直觀,下面我們將C++中的lambda函數(shù)語法規(guī)則做一個(gè)梳理。
????首先先看一段代碼,直觀感受一下lambda的使用。

#include <iostream>

template <typename T, typename R>
void foo(T func, R param)
{
    func(param);
}

void bar(int param)
{
    std::cout << "function param is :" << param << std::endl;
}

struct foobar
{
    void operator ()(int param)
    {
        std::cout << "functor param is :" << param << std::endl;
    }
};


int main()
{
    foo([](int param)->void 
    {
        std::cout << "lambda param is :"<<param<<std::endl;
    }, 123);

    foo(bar, 456);

    foo(foobar(), 789);
    return 0;
}

????上面代碼展示了一個(gè)模板函數(shù)接受三類可執(zhí)行代碼(函數(shù)、仿函數(shù)和lambda函數(shù))的示例。foo為模板函數(shù),它接受兩個(gè)參數(shù),第一參數(shù)是可執(zhí)行代碼,第二參數(shù)是第一參數(shù)的參數(shù)。我們的調(diào)用代碼展示了它的用法,它可以接受lambda函數(shù)、普通函數(shù)和仿函數(shù)??梢钥闯?,接受lambda函數(shù)版本的調(diào)用直接在調(diào)用處展開,這種方式比較直觀,如果習(xí)慣了java語言的同學(xué)應(yīng)該更有體會(huì)。
????lambda的基礎(chǔ)語法定義如下:

[capture](parameters) mutable ->return-type{statement}

其中,
1、[capture]:捕獲列表。它總是出現(xiàn)在lambda函數(shù)的開始位置。在編譯器看來[]是lambda的引出符號(hào),編譯器正式通過它來判斷接下來的代碼是否是lambda函數(shù)。捕獲列表能夠捕捉當(dāng)前上下文中的變量供給lambda函數(shù)使用。具體的capture列表中的語法,下面還會(huì)詳細(xì)講述。
2、(parameters):參數(shù)列表。它跟一般函數(shù)的參數(shù)列表一樣,使用規(guī)則也相同。在lambda中,如果不需要傳入?yún)?shù),可以省略。
3、mutable:修飾符。默認(rèn)情況下,lambda函數(shù)總是一個(gè)const函數(shù),mutable可以取消它的常量屬性。顯示指定mutable修飾符的時(shí)候,參數(shù)列表不能省略。
4、->return-type:返回值類型。->這個(gè)同C++11新引入的追蹤返回值類型的聲明是一致的,語法也是一致的。不同的是,處于方便,lambda函數(shù)在沒有返回值的情況下,可以省略掉(在某些編譯器可以推導(dǎo)出返回值類型的情況亦可省略)。
5、{statement}:函數(shù)體。與一般函數(shù)的函數(shù)體一致,額外可以使用捕獲列表中捕獲的變量。
????上面就是lambda函數(shù)的語法,可以看出2和3、4都是可選的,所以一個(gè)lambda函數(shù)可以簡(jiǎn)化成為下面的代碼

[]{std::cout<<"Hello Lambda\n";}

????lambda函數(shù)相較普通函數(shù)調(diào)用最便捷之處就是其捕獲列表,它可以通過值傳遞捕獲或者引用傳遞方式捕獲,直接在函數(shù)體內(nèi)訪問到上下文(一個(gè)代碼塊內(nèi))的變量。如果是普通函數(shù)的話,這些都要以參數(shù)形式傳遞進(jìn)去,使代碼十分冗長(zhǎng)。那么捕獲列表的具體語法可以歸納如下:
1、[a]表示值傳遞捕獲變量a(多個(gè)參數(shù)可以用逗號(hào)分隔)
2、[=]表示值傳遞捕獲上下文所有變量
3、[&a]表示引用傳遞捕獲變量a
4、[&]表示引用傳遞捕獲上下文所有變量
5、[this]表示值傳遞捕獲當(dāng)前的this指針
6、[=, &a, &b]表示值傳遞捕獲上下文所有變量,但是a、b變量以引用傳遞方式捕獲。
7、[&, a, this]表示引用傳遞捕獲上下文所有變量,但是a和this指針以值傳遞方式捕獲。

    char c = 'a';
    float d = 1.11f;
    foo([=](int param)->void
    {
        std::cout << "lambda param is :"<< param <<std::endl;
        std::cout << "lambda cap is :" << c << std::endl;
        std::cout << "lambda cap2 is :" << d << std::endl;
    }, 123);

上面代碼展示了捕獲列表的值傳遞用法,其余方式大同小異。

lambda函數(shù)和仿函數(shù)

????在C++98STL庫的實(shí)現(xiàn)中,大量的函數(shù)需要傳入回調(diào),而這些回調(diào)基本都是以模板參數(shù)的形式傳入。這樣的好處是既可以接受C編程習(xí)慣中的回調(diào)函數(shù),又可以接受C++方式的functor(仿函數(shù))?,F(xiàn)在有了lambda函數(shù),我們有了第三種選擇。文章最開始的例子實(shí)際上已經(jīng)展示了三種方式傳入給模板函數(shù)的情況,我們現(xiàn)在以STL中的for_each為例再來看一下lambda函數(shù)和仿函數(shù)之間的對(duì)比。

struct for_each_functor
{
    void operator ()(int param)
    {
        std::cout << param + 5 << std::endl;
    }
};


int main()
{
    std::vector<int> vec_foo;
    for (int i = 0; i < 10; ++i)
    {
        vec_foo.push_back(i);
    }
    std::for_each(vec_foo.begin(), vec_foo.end(), for_each_functor());
    std::for_each(vec_foo.begin(), vec_foo.end(),
        [](int param)->void
    {
        std::cout << param + 15 << std::endl;
    }
    );
    return 0;
}

????看一下上面的代碼,兩種for_each的調(diào)用,是不是感覺lambda版本的調(diào)用看起來更加簡(jiǎn)潔,并且實(shí)現(xiàn)起來也比functor版本簡(jiǎn)潔了一些。

最后

????lambda函數(shù)的語法比較簡(jiǎn)單,但是它跟實(shí)際應(yīng)用結(jié)合在一起就會(huì)發(fā)揮很大的作用,給程序編寫帶來很大的便利。后面我們將會(huì)介紹的基于C++11的線程池中,會(huì)極致利用lambda函數(shù)的便利性,使得我們可以用很少的代碼編寫一個(gè)極其方便、功能極其強(qiáng)大的線程池類。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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