最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++精要分析lambda表達(dá)式的使用

 更新時(shí)間:2022年05月09日 10:16:12   作者:程序猿阿諾  
Lambda表達(dá)式是現(xiàn)代C++在C ++ 11和更高版本中的一個(gè)新的語法糖 ,在C++11、C++14、C++17和C++20中Lambda表達(dá)的內(nèi)容還在不斷更新。 lambda表達(dá)式(也稱為lambda函數(shù))是在調(diào)用或作為函數(shù)參數(shù)傳遞的位置處定義匿名函數(shù)對象的便捷方法

引言

C++要走向現(xiàn)代語言,如果不支持lambda表達(dá)式,你很難認(rèn)為這門語言和現(xiàn)代有什么關(guān)系。幸好,從C++11標(biāo)準(zhǔn)起,它就實(shí)現(xiàn)了對lambda表達(dá)式的支持。

那么,什么是lambda表達(dá)式呢?

lambda表達(dá)式是匿名函數(shù),就是說不用定義函數(shù)名,函數(shù)實(shí)現(xiàn)可以直接嵌入在業(yè)務(wù)邏輯代碼中。諸如python、java、C#等語言,都將其作為基礎(chǔ)特性。

其優(yōu)點(diǎn)是提高了代碼的可讀性,對于一些無需重用的方法特別適合。例如在容器的迭代中實(shí)現(xiàn)特定的查詢邏輯。

語法與示例

C++11標(biāo)準(zhǔn)中,對于lambada表達(dá)式的定義如下:

[captures] (params) specifiers exception -> ret {body}

  • [captures] —— 捕獲列表,它用于捕獲當(dāng)前函數(shù)作用域的零個(gè)或多個(gè)變量,變量之間用逗號分隔。
  • {params} —— 可選參數(shù)列表,其語法與普通函數(shù)參數(shù)列表一致。如果不需要參數(shù),則可以忽略此項(xiàng)。
  • specifiers —— 可選限定符,可選值為mutable。其意義是可以在函數(shù)體內(nèi)修改按值捕獲的變量。
  • exception —— 可選異常說明符,可以使用noexcept來指明lambda是否會拋出異常。
  • ret —— 可選返回值類型,lambda使用返回類型后置的語法來表示返回類型。如果沒有返回值 ,則可忽略此部分。如果不指定返回類型,則編譯器會根據(jù)代碼實(shí)現(xiàn)為函數(shù)推導(dǎo)一個(gè)返回類型。
  • {body} —— 表達(dá)式的函數(shù)體,此部分與實(shí)現(xiàn)普通函數(shù)體一致。

從上面的定義可以看到,lambda表達(dá)式的語法多少有些與我們以往的認(rèn)知不太一樣。所以,我們直接上代碼來體會吧。

#include <iostream>
int main() {
    int x = 10;
    auto foo = [x](int y)->int { return x + y; };
    std::cout << foo(7) << std::endl;
}

各位不要手懶,務(wù)必打開IDE將這段代碼運(yùn)行一下,看看結(jié)果。然后再嘗試修改一下參數(shù)類型,或者返回類型。

增加mutable之后,對x變量進(jìn)行修改,看看會發(fā)生什么?

int main() {
    int x = 10;
    auto foo = [x](int y) mutable ->int { x++; return x + y; };
    std::cout << foo(7) << std::endl;
    std::cout << foo(7) << std::endl;
    std::cout << foo(7) << std::endl;
}

而一個(gè)最簡形式的lambda表達(dá)式,可以是 auto foo = [] { return 0; };。

所以大家以后看到類似語法,可不要大驚小怪了,還以為這是什么另類的數(shù)組訪問方式,或者琢磨->這個(gè)指針指向了個(gè)什么東西。

捕獲列表

毫無疑問,lambda表達(dá)式中,最反直覺的就是捕獲列表的定義。畢竟在我們的認(rèn)知里,中括號是用來定義數(shù)組并訪問數(shù)組元素的。

而且捕獲列表的諸多特性,也是面試中挖坑的好地方。我們先從作用域開始說起。

關(guān)于lambda表達(dá)式的作用域,有四個(gè)重點(diǎn):

  • 第一,捕獲列表的變量有兩個(gè)作用域,一是lambda定義的函數(shù)作用域,二是表達(dá)式函數(shù)體所在代碼的作用域;
  • 第二,在表達(dá)式函數(shù)體內(nèi),默認(rèn)情況下,被捕獲變量是只讀屬性。如需修改,則要添加mutable標(biāo)識;
  • 第三,在表達(dá)式函數(shù)體內(nèi),修改被捕獲變量的值,不影響原始變量的值;
  • 第四,被捕獲變量必須是非靜態(tài)局部變量。

好,為了加強(qiáng)印象,我們先從面試挖坑場景開始。請先看第一坑:

int main() {
    int x = 10;
    auto foo = [x](int y) ->int { x++; return x + y; };
    std::cout << foo(8) << std::endl;
}

問:上述代碼能通過編譯嗎?如果不能,是為什么?

答:不能。因?yàn)楦鶕?jù)規(guī)則一和二,在表達(dá)式函數(shù)體內(nèi),x變量是只讀,不能被修改。

好,上面的只是開胃菜,詭異的第二坑來了:

int main() {
    int x = 10;
    auto foo = [x](int y) mutable ->int {
        x++;
        std::cout << x << std::endl;
        return x + y;
    };
    foo(8);
    foo(8);
    std::cout << x << std::endl;
}

問:在上述代碼執(zhí)行完后,請說出所有std::cout語句輸出什么內(nèi)容?

答:根據(jù)規(guī)則三,分別輸出11,12,10。

所以大家可以看到,前兩次輸出是在表達(dá)式體內(nèi)對x值進(jìn)行修改,x的狀態(tài)是保留的了。但在函數(shù)體外,x變量的值仍然保持不變。千萬要記住這個(gè)規(guī)則,這就是存在兩個(gè)作用域所得到的結(jié)果。

后面我們會講解其實(shí)現(xiàn)原理,這樣就可以方便記憶這條規(guī)則了。

再來第三坑:

int y = 100;
int main() {
    static int x = 10;
    auto foo = [x, y](int z) ->int { return x + y + z; };
    std::cout << foo(8) << std::endl;
}

問:上述代碼有什么問題,應(yīng)該如何調(diào)整?

答:根據(jù)作用域規(guī)則四,x與y都不能作為lambda表達(dá)式的捕獲列表變量。在表達(dá)式函數(shù)體內(nèi)可以直接使用靜態(tài)或者全局變量,所以只要修改為auto foo = [](int z) ->int { return x + y + z; };即可。

雖然上面這段代碼放在gcc編譯器下不會報(bào)錯(cuò),只是出警告:capture of variable ‘x’ with non-automatic storage duration。但編譯器實(shí)際上是作了一次選擇,即認(rèn)為你的意圖是作為全局或靜態(tài)變量來使用。可如果你只是手誤或者忘了要調(diào)整代碼,那就會出現(xiàn)預(yù)料之外的運(yùn)行結(jié)果。

實(shí)際上,筆者所在公司就嚴(yán)格要求不能出現(xiàn)編譯警告,這對于防止運(yùn)行期出現(xiàn)偏差是非常重要的。

捕獲引用

上一節(jié)我們所講的,都是捕獲值的用法。那么想將變量作為引用傳遞進(jìn)lambda表達(dá)式,是否可以呢?

答案是肯定的,示例如下:

int main() {
    int x = 10;
    int y = 11;
    auto foo = [&x, &y](int z) mutable ->int {
        x++;
        y++;
        return x + y + z;
    };
    std::cout << foo(8) << std::endl;
    std::cout << x << std::endl;
    std::cout << y << std::endl;
}

可以看到,捕獲引用就是在變量前加上&符號即可。切記不要與取地址相混淆。被引用變量在函數(shù)體內(nèi)修改,也會影響函數(shù)體外同名變量的值,這一點(diǎn)與我們以往的認(rèn)知相同。

至于上述代碼結(jié)果,請各位先在腦海里執(zhí)行一遍,然后上機(jī)驗(yàn)證。

特殊用法

捕獲列表支持三種特殊情況,下面分別說明:

  • [this] —— 捕獲this指針,可以在類內(nèi)的lambda表達(dá)式函數(shù)體內(nèi)使用,以訪問成員變量和方法;
  • [=] —— 捕獲當(dāng)前作用域內(nèi)全部變量的值,包括this。當(dāng)變量較多時(shí),可使用此符號;
  • [&] —— 捕獲當(dāng)前作用域內(nèi)所有變量的引用,包括this。

先看[this]的示例:

class CaptureOne {
    public:
        void test() {
            auto foo = [this] { std::cout << x << std::endl; };
            foo();
        }
    private:
        int x = 100;
};
int main() {
    CaptureOne one;
    one.test();
}

建議大家在上面這個(gè)例子里繼續(xù)擴(kuò)展,例如增加一個(gè)類方法,看看在表達(dá)式函數(shù)中如何調(diào)用,以及執(zhí)行結(jié)果是什么。

再看[=]的示例:

int main() {
    int x = 10;
    int y = 11;
    int z = 12;
    auto foo = [=]() mutable ->int {
        x++;
        y++;
        return x + y + z;
    };
    std::cout << foo() << std::endl;
    std::cout << x << std::endl;
    std::cout << y << std::endl;
}

可以看到,這的確是方便了代碼書寫。如果表達(dá)式函數(shù)體內(nèi)的變量增加或減少,都不必再費(fèi)心思去調(diào)整捕獲列表了。

另外,不知道大家還注意到一個(gè)細(xì)節(jié)沒有,就是當(dāng)參數(shù)列表為空時(shí),如果存在mutable標(biāo)識,則()是不能省略的。

最后,[&]還是煩請各位自己去實(shí)踐并體驗(yàn)。

實(shí)現(xiàn)原理

C++多年老手,在上手lambda表達(dá)式的時(shí)候,應(yīng)該會馬上在腦海里跟函數(shù)對象關(guān)聯(lián)起來。

我們先從定義一個(gè)函數(shù)類開始說起。所謂函數(shù)類,就是定義一個(gè)類,然后重載operator ()。這樣可以將類對象作為函數(shù)一樣來調(diào)用。

示例如下:

class FuncOne {
    public:
        FuncOne(int x, int y) : valx(x), valy(y){}
        int operator () () {
            return valx + valy;
        }
    private:
        int valx;
        int valy;
};
int main() {
    FuncOne one(10, 20);
    std::cout << one() << std::endl;
}

上述代碼就是函數(shù)類的定義與函數(shù)對象的使用方法。而C++11標(biāo)準(zhǔn)中的lambda表達(dá)式,其實(shí)就是在編譯器在編譯期生成一個(gè)閉包類(可以理解為類似于FuncOne的類),然后在運(yùn)行時(shí)由這個(gè)閉包類生成一個(gè)對象,稱之為閉包。

而閉包就是一個(gè)匿名的函數(shù)對象,它包含了定義時(shí)作用域的上下文。這樣我們就會發(fā)現(xiàn)lambda表達(dá)式,其實(shí)就是C++11給我們提供的一個(gè)語法糖。

現(xiàn)在再回頭去理解捕獲列表的四條原則,是否有恍然大悟之感?理解了原理,對于原則就不用死記硬背了,祝各位面試好運(yùn)!

應(yīng)用

當(dāng)然,我們不能滿足于只過面試關(guān),還應(yīng)當(dāng)在工作中用好它才行。做C++開發(fā)的,用好STL是基本功,而lambda表達(dá)式與STL相結(jié)合,可以簡化代碼,發(fā)揮出強(qiáng)大的威力來。

先看一個(gè)需求:我們要在一組vector列表中,打印可以整除4的數(shù)。

示例代碼:

#include        <iostream>
#include        <vector>
#include        <algorithm>
int main() {
    std::vector<int> num_list = {1, 3, 9, 10, 12, 17, 18};
    std::cout << *std::find_if(num_list.cbegin(), num_list.cend(),
            [](int i) { return (i % 4) == 0;}) << std::endl;
}

大家可以看到,如果是在以前,要實(shí)現(xiàn)這個(gè)功能,需要額外寫多少代碼。

也希望各位能從這個(gè)簡單示例開始,回頭去梳理自己以前寫的代碼,可以怎樣優(yōu)化結(jié)構(gòu)并提高效率。并且在將來的開發(fā)過程中,不斷修煉功夫,成為C++大咖!

到此這篇關(guān)于C++精要分析lambda表達(dá)式的使用的文章就介紹到這了,更多相關(guān)C++lambda內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • c++實(shí)現(xiàn)堆排序的示例代碼

    c++實(shí)現(xiàn)堆排序的示例代碼

    本文主要介紹了c++實(shí)現(xiàn)堆排序的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • C++中的Lambda表達(dá)式詳解

    C++中的Lambda表達(dá)式詳解

    這篇文章主要介紹了C++中的Lambda表達(dá)式詳解,本文講解了基本語法、Lambda的使用等內(nèi)容,需要的朋友可以參考下
    2014-10-10
  • C++?Cmake使用詳細(xì)教程(看這一篇就夠了!)

    C++?Cmake使用詳細(xì)教程(看這一篇就夠了!)

    CMake是一個(gè)比make更高級的編譯配置工具,它可以根據(jù)不同平臺、不同的編譯器,生成相應(yīng)的Makefile或者vcproj項(xiàng)目,下面這篇文章主要給大家介紹了關(guān)于C++?Cmake使用的相關(guān)資料,需要的朋友可以參考下
    2023-03-03
  • C++ 搬水果貪心算法實(shí)現(xiàn)代碼

    C++ 搬水果貪心算法實(shí)現(xiàn)代碼

    這篇文章主要介紹了C++ 搬水果貪心算法實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • C語言實(shí)現(xiàn)類似wget的進(jìn)度條效果

    C語言實(shí)現(xiàn)類似wget的進(jìn)度條效果

    這篇文章主要介紹了C語言實(shí)現(xiàn)類似wget的進(jìn)度條效果的方法,主要是讓大家可以熟練的使用轉(zhuǎn)移符\r,這里推薦給大家,需要的小伙伴參考下。
    2015-03-03
  • C++ 空指針解引用的解決方法

    C++ 空指針解引用的解決方法

    空指針解引用是一種常見且嚴(yán)重的錯(cuò)誤,它通常由于指針未初始化、被設(shè)置為nullptr或指向無效地址引起,本文主要介紹了C++ 空指針解引用的解決方法,感興趣的可以了解一下
    2024-08-08
  • 快速學(xué)習(xí)C語言中for循環(huán)語句的基本使用方法

    快速學(xué)習(xí)C語言中for循環(huán)語句的基本使用方法

    這篇文章主要簡單介紹了C語言中for循環(huán)語句的基本使用方法,是C語言入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-11-11
  • 在C語言項(xiàng)目中有效進(jìn)行異常處理機(jī)制(最新推薦)

    在C語言項(xiàng)目中有效進(jìn)行異常處理機(jī)制(最新推薦)

    本文將探討在C語言項(xiàng)目中如何設(shè)計(jì)和實(shí)現(xiàn)錯(cuò)誤處理機(jī)制,以確保程序的健壯性和可靠性,感興趣的朋友一起看看吧
    2025-03-03
  • C++中返回指向函數(shù)的指針示例

    C++中返回指向函數(shù)的指針示例

    int (*ff(int)) (int *,int);表示:ff(int)是一個(gè)函數(shù),帶有一個(gè)int型的形參,該函數(shù)返回int (*) (int *,int),它是一個(gè)指向函數(shù)的指針,所指向的函數(shù)返回int型并帶有兩個(gè)分別是Int*和int型的形參
    2013-09-09
  • C語言新手練習(xí)之多維數(shù)組、結(jié)構(gòu)體及函數(shù)

    C語言新手練習(xí)之多維數(shù)組、結(jié)構(gòu)體及函數(shù)

    這篇文章主要給大家介紹了關(guān)于C語言新手練習(xí)之多維數(shù)組、結(jié)構(gòu)體及函數(shù)的相關(guān)資料,這些內(nèi)容在我們?nèi)粘i_發(fā)中經(jīng)常會遇到的,需要的朋友可以參考下
    2021-06-06

最新評論

松溪县| 霍林郭勒市| 儋州市| 南充市| 宁强县| 武乡县| 公安县| 奉新县| 乌兰浩特市| 天柱县| 应城市| 福鼎市| 寿光市| 宣城市| 大余县| 阿拉善盟| 辛集市| 武清区| 宁明县| 莱芜市| 天长市| 乌审旗| 邵阳市| 顺义区| 胶州市| 鞍山市| 东明县| 富平县| 上犹县| 林芝县| 永嘉县| 永德县| 香港 | 南投市| 阳朔县| 会宁县| 葵青区| 兴文县| 崇州市| 澄城县| 宝坻区|