自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

編譯器如何實(shí)現(xiàn)lambda表達(dá)式?

開發(fā) 后端
lambda表達(dá)式在C++11中引入,用lambda表達(dá)式表示匿名函數(shù)非常方便,語法很簡單,而且可以使代碼更緊湊,更易于閱讀。

[[404386]]

本文轉(zhuǎn)載自微信公眾號「程序喵大人」,作者程序喵大人。轉(zhuǎn)載本文請聯(lián)系程序喵大人公眾號。

lambda表達(dá)式在C++11中引入,用lambda表達(dá)式表示匿名函數(shù)非常方便,語法很簡單,而且可以使代碼更緊湊,更易于閱讀。

lambda表達(dá)式更適合定義小點(diǎn)的回調(diào)內(nèi)聯(lián)去傳遞給其他函數(shù),而不是在其他地方定義個(gè)完整的函數(shù)對象,并在其重載函數(shù)調(diào)用運(yùn)算符中實(shí)現(xiàn)回調(diào)邏輯。所有的邏輯都在一個(gè)位置上,容易理解和維護(hù),lambda表達(dá)式可以接收參數(shù),可返回值,可模板化,可通過值或引用的方式訪問外面的變量,相當(dāng)?shù)撵`活。

關(guān)于lambda表達(dá)式的使用,我之前介紹過,可以看這篇文章搞定c++11新特性std::function和lambda表達(dá)式,這里一筆帶過:

  1. auto lambda { []{ cout << "Hello \n"; } }; 
  2. lambda(); 

那這個(gè)lambda表達(dá)式是如何實(shí)現(xiàn)的呢?

編譯器會將lambda表達(dá)式自動轉(zhuǎn)換為函數(shù)對象,編譯器會為此生成個(gè)唯一的命名。上面的示例會自動的轉(zhuǎn)換成下面這樣的函數(shù)對象,注意函數(shù)調(diào)用運(yùn)算符是個(gè)const方法,返回類型是auto,這方便編譯器根據(jù)方法體自動推導(dǎo)出返回類型。

  1. class CompilerGeneratedName { 
  2.     public
  3.         auto operator()() const { cout << "Hello \n"; } 
  4. }; 

編譯器生成的lambda閉包名字會是一些奇怪的名子,例如__Lambda_21Za等,我們沒法知道這個(gè)名字,我們也不需要知道這個(gè)名字。

lambda表達(dá)式可以接收參數(shù),參數(shù)在圓括號之間指定,就像普通函數(shù)一樣,下面是例子:

  1. auto lambda { 
  2.     [](int value){ cout << "The value is " << value << endl; } }; 
  3. lambda(42); 

如果lambda表達(dá)式不接收任何參數(shù),可以指定空括號或者直接省略括號。

編譯器會將上面的lambda表達(dá)式自動轉(zhuǎn)換為下面這樣:

  1. class CompilerGeneratedName { 
  2.     public
  3.         auto operator()(int value) const { 
  4.             cout << "The value is " << value << endl; } 
  5. }; 

lambda表達(dá)式可以返回值,返回類型在箭頭后面指定,稱為尾返回類型,看代碼:

  1. auto lambda { [](int a, int b) -> { return a + b; } }; 
  2. int sum = lambda(11, 22); 

編譯器轉(zhuǎn)成這樣:

  1. class CompilerGeneratedName { 
  2.     public
  3.         auto operator()(int a, int b) const { return a + b; } 
  4. }; 

那能捕獲變量的lambda表達(dá)式是怎么實(shí)現(xiàn)的呢?

比如下面的lambda表達(dá)式:

  1. double data { 1.234 }; 
  2. auto lambda { [data]{ cout << "Data = " << data << endl; } } 

捕獲的變量會變?yōu)閘ambda閉包的數(shù)據(jù)成員,值捕獲的變量被拷貝到仿函數(shù)的數(shù)據(jù)成員中,編譯器的行為是這樣:

  1. class CompilerGeneratedName 
  2.     public
  3.         CompilerGeneratedName(const double& d) : data { d } {} 
  4.         auto operator()() const { cout << "Data = " << data << endl; } 
  5.     private: 
  6.         double data; 
  7. }; 

還有泛型lambda表達(dá)式:

  1. auto areEqual { [](const auto& value1, const auto& value2) { 
  2.     return value1 == value2; } }; 
  3.  
  4. vector values1 { 2, 5, 6, 9, 10, 1, 1 }; 
  5. vector values2 { 4, 4, 2, 9, 0, 3, 1 }; 
  6. findMatches(values1, values2, areEqual, printMatch); 

編譯器會轉(zhuǎn)換成這樣:

  1. class CompilerGeneratedName { 
  2.     public
  3.         template <typename T1, typename T2> 
  4.         auto operator()(const T1& value1, const T2& value2) const 
  5. return value1 == value2; } 
  6. }; 

如果findMatches()函數(shù)中的參數(shù)是其他類型,那么areEqual泛型表達(dá)式不需要任何更改就可以直接繼續(xù)使用。

聊完了編譯器怎么實(shí)現(xiàn)的lambda表達(dá)式,下面介紹下lambda表達(dá)式的捕獲方式。

捕獲方式

有兩種方法從閉包作用域捕獲所有變量,稱為默認(rèn)捕獲:

  • [=] 值捕獲所有變量
  • [&]引用捕獲所有變量
  • 注意:
  • 使用引用方式捕獲變量時(shí),必須確保引用在lambda表達(dá)式執(zhí)行期間是合法的。
  • 當(dāng)使用默認(rèn)捕獲時(shí),通過值(=)或引用(&),只有那些在lambda 表達(dá)式中真正使用的變量才會被捕獲,未使用的變量不會被捕獲。
  • 不建議使用默認(rèn)捕獲,即使默認(rèn)捕獲只捕獲那些在lambda 表達(dá)式主體中真正使用的變量,通過使用=默認(rèn)捕獲,可能會意外的導(dǎo)致高代價(jià)的拷貝,通過使用&默認(rèn)捕獲,可能意外的在閉包作用域中修改變量,建議明確指定想要捕獲哪些變量以及捕獲方式。

再注意:全局變量總是通過引用捕獲,例如在下面的代碼中,默認(rèn)捕獲用于按值捕獲所有內(nèi)容,然而全局變量global其實(shí)是通過引用捕獲的,在執(zhí)行l(wèi)ambda 后它的值被更改。

  1. int global { 42 }; 
  2. int main() { 
  3.     auto lambda { [=] { global = 2; } }; 
  4.     lambda(); 
  5.     // 這里global是2! 

不允許像下面這樣顯式捕獲全局變量,這樣編譯會失?。?/p>

  1. auto lambda { [global] { global = 2; } }; // error 

所以,建議不要使用全局變量。

對于不捕獲任何內(nèi)容的lambda表達(dá)式,編譯器自動提供轉(zhuǎn)換運(yùn)算符,將lambda 表達(dá)式轉(zhuǎn)換為函數(shù)指針。這樣的lambda表達(dá)式可作為參數(shù)傳遞給其他函數(shù)。

在C++20中關(guān)于lambda表達(dá)式也做了一些更新,可以模板化lambda表達(dá)式,也可以默認(rèn)構(gòu)造、拷貝和賦值lambda表達(dá)式,像下面這樣:

  1. auto lambda { [](int a, int b) { return a + b; } }; 
  2. decltype(lambda) lambda2; // 默認(rèn)構(gòu)造 
  3. auto copy { lambda }; // 拷貝構(gòu)造 
  4. copy = lambda2; // 拷貝賦值 

 

這不是本文的主題,就不過多介紹了。

 

責(zé)任編輯:武曉燕 來源: 程序喵大人
相關(guān)推薦

2009-08-10 09:41:07

.NET Lambda

2025-03-06 08:16:08

lambda表達(dá)式變量

2009-09-11 09:48:27

Linq Lambda

2009-09-09 13:01:33

LINQ Lambda

2009-09-15 15:18:00

Linq Lambda

2022-12-05 09:31:51

接口lambda表達(dá)式

2012-06-26 10:03:58

JavaJava 8lambda

2009-08-27 09:44:59

C# Lambda表達(dá)

2009-09-17 10:40:22

Linq Lambda

2009-09-15 17:30:00

Linq Lambda

2009-09-17 09:44:54

Linq Lambda

2024-03-25 13:46:12

C#Lambda編程

2009-10-12 10:11:08

Lambda表達(dá)式編寫

2009-04-29 09:05:59

Lambda抽象代表.NET

2009-08-26 16:17:23

C# Lambda表達(dá)

2009-08-31 17:11:37

Lambda表達(dá)式

2009-08-27 09:57:50

C# Lambda表達(dá)

2009-09-17 09:09:50

Lambda表達(dá)式Linq查詢

2013-04-10 10:58:19

LambdaC#

2013-04-07 15:44:26

Java8Lambda
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號