C++之Lambda表达式
1. 概述
C++ 11 中的 Lambda 表達(dá)式用于定義并創(chuàng)建匿名的函數(shù)對(duì)象,以簡(jiǎn)化編程工作。
Lambda 的語法形式如下:
可以看到,Lambda 主要分為五個(gè)部分:[函數(shù)對(duì)象參數(shù)]、(操作符重載函數(shù)參數(shù))、mutable 或 exception 聲明、-> 返回值類型、{函數(shù)體}.
2. Lambda 語法分析
2.1 [函數(shù)對(duì)象參數(shù)]
標(biāo)識(shí)一個(gè) Lambda 表達(dá)式的開始,這部分必須存在,不能省略。函數(shù)對(duì)象參數(shù)是傳遞給編譯器自動(dòng)生成的函數(shù)對(duì)象類的構(gòu)造
函數(shù)的。函數(shù)對(duì)象參數(shù)只能使用那些到定義 Lambda 為止時(shí) Lambda 所在作用范圍內(nèi)可見的局部變量(包括 Lambda 所在類
的 this)。函數(shù)對(duì)象參數(shù)有以下形式:
- 空。沒有任何函數(shù)對(duì)象參數(shù)。
- =。函數(shù)體內(nèi)可以使用 Lambda 所在范圍內(nèi)所有可見的局部變量(包括 Lambda 所在類的 this),并且是值傳遞方式(相
當(dāng)于編譯器自動(dòng)為我們按值傳遞了所有局部變量)。 - &。函數(shù)體內(nèi)可以使用 Lambda 所在范圍內(nèi)所有可見的局部變量(包括 Lambda 所在類的 this),并且是引用傳遞方式
(相當(dāng)于是編譯器自動(dòng)為我們按引用傳遞了所有局部變量)。 - this。函數(shù)體內(nèi)可以使用 Lambda 所在類中的成員變量。
- a。將 a 按值進(jìn)行傳遞。按值進(jìn)行傳遞時(shí),函數(shù)體內(nèi)不能修改傳遞進(jìn)來的 a 的拷貝,因?yàn)槟J(rèn)情況下函數(shù)是 const 的,要
修改傳遞進(jìn)來的拷貝,可以添加 mutable 修飾符。 - &a。將 a 按引用進(jìn)行傳遞。
- a,&b。將 a 按值傳遞,b 按引用進(jìn)行傳遞。
- =,&a,&b。除 a 和 b 按引用進(jìn)行傳遞外,其他參數(shù)都按值進(jìn)行傳遞。
- &,a,b。除 a 和 b 按值進(jìn)行傳遞外,其他參數(shù)都按引用進(jìn)行傳遞。
2.2 (操作符重載函數(shù)參數(shù))
標(biāo)識(shí)重載的 () 操作符的參數(shù),沒有參數(shù)時(shí),這部分可以省略。參數(shù)可以通過按值(如: (a, b))和按引用 (如: (&a, &b)) 兩種
方式進(jìn)行傳遞。
2.3 mutable 或 exception 聲明
這部分可以省略。按值傳遞函數(shù)對(duì)象參數(shù)時(shí),加上 mutable 修飾符后,可以修改傳遞進(jìn)來的拷貝(注意是能修改拷貝,而不是
值本身)。exception 聲明用于指定函數(shù)拋出的異常,如拋出整數(shù)類型的異常,可以使用 throw(int)。
2.4 -> 返回值類型
標(biāo)識(shí)函數(shù)返回值的類型,當(dāng)返回值為 void,或者函數(shù)體中只有一處 return 的地方(此時(shí)編譯器可以自動(dòng)推斷出返回值類型)
時(shí),這部分可以省略。
2.5 {函數(shù)體}
標(biāo)識(shí)函數(shù)的實(shí)現(xiàn),這部分不能省略,但函數(shù)體可以為空。
3. 示例
[] (int x, int y) { return x + y; } // 隱式返回類型 [] (int& x) { ++x; } // 沒有 return 語句 -> Lambda 函數(shù)的返回類型是 'void' [] () { ++global_x; } // 沒有參數(shù),僅訪問某個(gè)全局變量 [] { ++global_x; } // 與上一個(gè)相同,省略了 (操作符重載函數(shù)參數(shù))可以像下面這樣顯示指定返回類型:
[] (int x, int y) -> int { int z = x + y; return z; }在這個(gè)例子中創(chuàng)建了一個(gè)臨時(shí)變量 z 來存儲(chǔ)中間值。和普通函數(shù)一樣,這個(gè)中間值不會(huì)保存到下次調(diào)用。什么也不返回的
Lambda 函數(shù)可以省略返回類型,而不需要使用 -> void 形式。
Lambda 函數(shù)可以引用在它之外聲明的變量. 這些變量的集合叫做一個(gè)閉包. 閉包被定義在 Lambda 表達(dá)式聲明中的方括
號(hào) [] 內(nèi)。這個(gè)機(jī)制允許這些變量被按值或按引用捕獲。如下圖的例子:
3.1 示例 1
std::vector<int> some_list; int total = 0; for (int i = 0; i < 5; ++i) some_list.push_back(i); std::for_each(begin(some_list), end(some_list), [&total](int x) {total += x; });此例計(jì)算 list 中所有元素的總和。變量 total 被存為 Lambda 函數(shù)閉包的一部分。因?yàn)樗菞W兞?#xff08;局部變量)total 引
用,所以可以改變它的值。
3.2 示例 2
std::vector<int> some_list; int total = 0; int value = 5; std::for_each(begin(some_list), end(some_list), [&, value, this](int x) {total += x * value * this->some_func(); });此例中 total 會(huì)存為引用, value 則會(huì)存一份值拷貝。對(duì) this 的捕獲比較特殊,它只能按值捕獲。this 只有當(dāng)包含它的最靠近
它的函數(shù)不是靜態(tài)成員函數(shù)時(shí)才能被捕獲。對(duì) protect 和 private 成員來說,這個(gè) Lambda 函數(shù)與創(chuàng)建它的成員函數(shù)有相同
的訪問控制。如果 this 被捕獲了,不管是顯式還是隱式的,那么它的類的作用域?qū)?Lambda 函數(shù)就是可見的。訪問 this 的
成員不必使用 this-> 語法,可以直接訪問。
4. 總結(jié)
不同編譯器的具體實(shí)現(xiàn)可以有所不同,但期望的結(jié)果是: 按引用捕獲的任何變量,Lambda 函數(shù)實(shí)際存儲(chǔ)的應(yīng)該是這些變量在
創(chuàng)建這個(gè) Lambda 函數(shù)的函數(shù)的棧指針,而不是 Lambda 函數(shù)本身?xiàng)W兞康囊谩2还茉鯓?#xff0c;因?yàn)榇蠖鄶?shù) Lambda 函數(shù)都
很小且在局部作用中,與候選的內(nèi)聯(lián)函數(shù)很類似,所以按引用捕獲的那些變量不需要額外的存儲(chǔ)空間。
如果一個(gè)閉包含有局部變量的引用,在超出創(chuàng)建它的作用域之外的地方被使用的話,這種行為是未定義的!
Lambda 函數(shù)是一個(gè)依賴于實(shí)現(xiàn)的函數(shù)對(duì)象類型,這個(gè)類型的名字只有編譯器知道. 如果用戶想把 lambda 函數(shù)做為一個(gè)參數(shù)來
傳遞, 那么形參的類型必須是模板類型或者必須能創(chuàng)建一個(gè) std::function 類似的對(duì)象去捕獲 lambda 函數(shù).使用 auto 關(guān)鍵字
可以幫助存儲(chǔ) lambda 函數(shù),
這里有一個(gè)例子, 把匿名函數(shù)存儲(chǔ)在變量、數(shù)組或 vector 中,并把它們當(dāng)做命名參數(shù)來傳遞
一個(gè)沒有指定任何捕獲的 lambda 函數(shù),可以顯式轉(zhuǎn)換成一個(gè)具有相同聲明形式函數(shù)指針.所以,像下面這樣做是合法的:
auto a_lambda_func = [](int x) { /* ... */ }; void (*func_ptr)(int) = a_lambda_func; func_ptr(4); // calls the lambda分類:?C++
總結(jié)
以上是生活随笔為你收集整理的C++之Lambda表达式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python中发送带附件的邮件,pyth
- 下一篇: s3c2440移植MQTT