C++ lambda表達式詳解

C++ lambda表達式詳解

C++11 lambda表達式精講

[ capture ] ( params ) opt -> ret { body; };

capture 是捕獲列表,params 是參數表,opt 是函數選項,ret 是返回值類型,body是函數體

一個完整的 lambda 表達式看起來像這樣:

auto f = [](int a) -> int { return a + 1; };
std::cout << f(1) << std::endl;  // 輸出: 2

lambda 表達式還可以通過捕獲列表捕獲一定范圍內的變量:

  • [] 不捕獲任何變量
  • [&] 捕獲外部作用域中所有變量,并作為引用在函數體中使用(按引用捕獲)
  • [=] 捕獲外部作用域中所有變量,并作為副本在函數體中使用(按值捕獲)
  • [=,&foo] 按值捕獲外部作用域中所有變量,并按引用捕獲 foo 變量
  • [bar] 按值捕獲 bar 變量,同時不捕獲其他變量
  • [this] 捕獲當前類中的 this 指針,讓 lambda 表達式擁有和當前類成員函數同樣的訪問權限。如果已經使用了 & 或者 =,就默認添加此選項。捕獲 this 的目的是可以在 lamda 中使用當前類的成員函數和成員變量
class A
{public:int i_ = 0;void func(int x, int y){auto x1 = []{ return i_; };                    // error,沒有捕獲外部變量auto x2 = [=]{ return i_ + x + y; };           // OK,捕獲所有外部變量auto x3 = [&]{ return i_ + x + y; };           // OK,捕獲所有外部變量auto x4 = [this]{ return i_; };                // OK,捕獲this指針auto x5 = [this]{ return i_ + x + y; };        // error,沒有捕獲x、yauto x6 = [this, x, y]{ return i_ + x + y; };  // OK,捕獲this指針、x、yauto x7 = [this]{ return i_++; };              // OK,捕獲this指針,并修改成員的值}
};
int a = 0, b = 1;
auto f1 = []{ return a; };               // error,沒有捕獲外部變量
auto f2 = [&]{ return a++; };            // OK,捕獲所有外部變量,并對a執行自加運算
auto f3 = [=]{ return a; };              // OK,捕獲所有外部變量,并返回a
auto f4 = [=]{ return a++; };            // error,a是以復制方式捕獲的,無法修改
auto f5 = [a]{ return a + b; };          // error,沒有捕獲變量b
auto f6 = [a, &b]{ return a + (b++); };  // OK,捕獲a和b的引用,并對b做自加運算
auto f7 = [=, &b]{ return a + (b++); };  // OK,捕獲所有外部變量和b的引用,并對b做自加運算

從上例中可以看到,lambda 表達式的捕獲列表精細地控制了 lambda 表達式能夠訪問的外部變量,以及如何訪問這些變量

需要注意的是,默認狀態下 lambda 表達式無法修改通過復制方式捕獲的外部變量。如果希望修改這些變量的話,我們需要使用引用方式進行捕獲

一個容易出錯的細節是關于 lambda 表達式的延遲調用的:

int a = 0;
auto f = [=]{ return a; };      // 按值捕獲外部變量
a += 1;                         // a被修改了
std::cout << f() << std::endl;  // 輸出?

在這個例子中,lambda 表達式按值捕獲了所有外部變量。在捕獲的一瞬間,a 的值就已經被復制到f中了。之后 a 被修改,但此時 f 中存儲的 a 仍然還是捕獲時的值,因此,最終輸出結果是 0

如果希望 lambda 表達式在調用時能夠即時訪問外部變量,我們應當使用引用方式捕獲

從上面的例子中我們知道,按值捕獲得到的外部變量值是在 lambda 表達式定義時的值。此時所有外部變量均被復制了一份存儲在 lambda 表達式變量中。此時雖然修改 lambda 表達式中的這些外部變量并不會真正影響到外部,我們卻仍然無法修改它們

那么如果希望去修改按值捕獲的外部變量應當怎么辦呢?這時,需要顯式指明 lambda 表達式為 mutable:

int a = 0;
auto f1 = [=]{ return a++; };             // error,修改按值捕獲的外部變量
auto f2 = [=]() mutable { return a++; };  // OK,mutable

需要注意的一點是,被 mutable 修飾的 lambda 表達式就算沒有參數也要寫明參數列表

聲明式的編程風格,簡潔的代碼

就地定義匿名函數,不再需要定義函數對象,大大簡化了標準庫算法的調用。比如,在 C++11 之前,我們要調用 for_each 函數將 vector 中的偶數打印出來,如下所示

class CountEven
{int& count_;
public:CountEven(int& count) : count_(count) {}void operator()(int val){if (!(val & 1))       // val % 2 == 0{++ count_;}}
};
std::vector<int> v = { 1, 2, 3, 4, 5, 6 };
int even_count = 0;
for_each(v.begin(), v.end(), CountEven(even_count));
std::cout << "The number of even is " << even_count << std::endl;

這樣寫既煩瑣又容易出錯。有了 lambda 表達式以后,我們可以使用真正的閉包概念來替換掉這里的仿函數,代碼如下:

std::vector<int> v = { 1, 2, 3, 4, 5, 6 };
int even_count = 0;
for_each( v.begin(), v.end(), [&even_count](int val){if (!(val & 1))  // val % 2 == 0{++ even_count;}});
std::cout << "The number of even is " << even_count << std::endl;

lambda 表達式的價值在于,就地封裝短小的功能閉包,可以極其方便地表達出我們希望執行的具體操作,并讓上下文結合得更加緊密

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/13299.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/13299.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/13299.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

醫院污水一體化處理設備有哪些

醫院污水一體化處理設備通常包括以下幾個主要組件&#xff1a; 預處理單元&#xff1a;用于去除污水中的固體懸浮物、顆粒物、油脂等&#xff0c;常見的預處理單元包括格柵、沉砂池、油水分離器等。生物處理單元&#xff1a;用于降解有機物質和去除氮、磷等營養物質。常見的生物…

7D-RESAR性能工程:術語表

文章目錄 1. 前言1.1. 編寫目的1.2. 適應范圍與對象 2. 術語表2.1. RESAR性能工程2.2. 性能測試2.3. 性能項目2.4. 性能項目方案2.5. 性能項目計劃2.6. 性能需求類術語2.6.1. 性能需求/指標2.6.2. 并發用戶2.6.3. 在線用戶2.6.4. 并發度&#xff08;并發率&#xff09;2.6.5. 事…

Kubernetes進階對象Deployment、DaemonSet、Service

Deployment Pod 在 YAML 里使用“containers”就可以任意編排容器&#xff0c;而且還有一個“restartPolicy”字段&#xff0c;默認值就是 Always&#xff0c;可以監控 Pod 里容器的狀態&#xff0c;一旦發生異常&#xff0c;就會自動重啟容器。 不過&#xff0c;“restartPo…

Java小游戲之湯姆貓

背景&#xff1a; 博主寫過羊了個羊小游戲&#xff0c;客戶覺得羊了個羊同學寫過了&#xff0c;想換一個&#xff0c;于是筆者想到了湯姆貓。就是那個以前在蘋果手機上的貓。 過程&#xff1a; 初始會有一個貓的圖片展示&#xff0c;然后你點擊按鈕&#xff0c;貓會有不同動作…

C++進階之路:何為默認構造函數與析構函數(類與對象_中篇)

?? 歡迎大家來訪Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭?&#xff5e;?? &#x1f31f;&#x1f31f; 歡迎各位親愛的讀者&#xff0c;感謝你們抽出寶貴的時間來閱讀我的文章。 我是Srlua小謝&#xff0c;在這里我會分享我的知識和經驗。&am…

Web3與物聯網:構建智能連接的數字世界

引言 隨著互聯網的不斷發展&#xff0c;物聯網&#xff08;Internet of Things, IoT&#xff09;作為一種新興的信息技術&#xff0c;正在逐漸滲透到我們的生活和工作中。而隨著Web3的興起&#xff0c;物聯網將迎來新的發展機遇。本文將探討Web3與物聯網的結合&#xff0c;如何…

如何在職場中構建穩固地位:持續學習、拓展人脈與職業規劃

在日益激烈的職場競爭中&#xff0c;保持一種穩健且前瞻性的狀態是至關重要的&#xff0c;它可以幫助我們在各種“裁員潮”中保持相對安全的位置。以下是一些建議&#xff0c;幫助我們判斷和維持在職場中的安全位置&#xff1a; 首先&#xff0c;持續學習和提升技能是關鍵。職場…

2024年NOC大賽創客智慧(西瓜創客)圖形化復賽編程真題模擬試卷包含答案

NOC 復賽圖形化模擬題 【題目要求】 1、添加角色小貓和“Balloon1”角色氣球(大小 70) 2、添加背景“Boardwalk” 3、點擊綠旗,角色初始位置如圖,小貓從舞臺左側出發,向舞臺右 側移動,移動過程中不斷切換造型 4、當小貓碰到氣球角色,小貓停止移動,氣球逐漸向舞臺上方…

FFmpeg開發筆記(二十七)解決APP無法訪問ZLMediaKit的直播鏈接問題

上一篇文章介紹了如何通過ZLMediaKit實現視頻推拉流&#xff0c;并使用VLC播放器驗證視頻直播地址。即使不用VLC播放器&#xff0c;直接在Qt工程的C代碼中調用FFmpeg的API&#xff0c;也能訪問ZLMediaKit的直播地址&#xff0c;并正常渲染視頻畫面。關于如何在Qt工程中引入FFmp…

Oracle中全量CHECKPOINT和增量CHECKPOINT的區別與作用

全量CHECKPOINT和增量CHECKPOINT對用戶都是透明的&#xff0c;而增量CHECKPOINT只不過是將全量CHECKPOINT要寫的臟塊分時間分批次寫到數據文件中而已&#xff0c;此操作可以極大地減少對數據庫性能的影響。 全量CHECKPOINT 全量CHECKPOINT是指DBWR進程將臟緩沖區列表中的臟塊一…

Spring Boot集成Security快速入門Demo

1.什么是Security&#xff1f; Spring Security是一個Java框架&#xff0c;用于保護應用程序的安全性。它提供了一套全面的安全解決方案&#xff0c;包括身份驗證、授權、防止攻擊等功能。Spring Security基于過濾器鏈的概念&#xff0c;可以輕松地集成到任何基于Spring的應用…

ifconfig 無輸出

https://www.cnblogs.com/YYFaGe/p/14482813.html YYFaGe 博客園首頁聯系管理隨筆 - 56 文章 - 0 評論 - 2 閱讀 - 94650 ifconfig 無輸出 在終端執行ifconfig發現無任何輸出&#xff0c;也無報錯&#xff08;基于hi3559av100開發板&#xff09;。 1、參考這個連接解決&…

月薪3萬,沉迷“薅羊毛”

在網購江湖中&#xff0c;蟹老板是一位擁有十年經驗的資深“羊毛黨”。 他不僅是位精明的數學家&#xff0c;更是一位高效的“生產線”工人&#xff0c;專注于各大網購平臺的優惠機制。每逢618大促&#xff0c;他總能憑借超凡的洞察力和手速&#xff0c;輕松斬獲豐厚的“羊毛”…

peft+llama3訓練自定義數據

要微調自己的模型訓練 LLaMA 3&#xff0c;則需要準備一個 JSON 格式的數據集&#xff0c;其中每個條目包含輸入文本和相應的標簽&#xff08;如果有的話&#xff09;。以下是一個 JSON 數據集的示例格式&#xff1a; [{"input": "這是一個輸入樣本。",&q…

17.高并發場景下CAS效率的優化

文章目錄 高并發場景下CAS效率的優化1.空間換時間&#xff08;LongAdder&#xff09;2.對比LongAdder和AtomicLong執行效率2.1.AtmoictLong2.2.LongAdder2.3.比對 3.LongAdder原理3.1.基類Striped64內部的三個重要成員3.2.LongAdder.add()方法3.3.LongAdder中longAccumulate()方…

pytorch-13_1 深度學習之數據準備

1、手動實現訓練集和測試集的切分 1. data_split()函數 接下來我們開始實踐模型評估過程,首先是對訓練集和測試集的劃分,我們嘗試創建一個切分訓練集和測試集的函數。 def data_split(features, labels, rate=0.7):"""訓練集和測試集切分函數:param feature…

搜索二維矩陣 - LeetCode 熱題 64

大家好&#xff01;我是曾續緣&#x1f9e1; 今天是《LeetCode 熱題 100》系列 發車第 64 天 二分查找第 2 題 ??點贊 &#x1f44d; 收藏 ?再看&#xff0c;養成習慣 搜索二維矩陣 給你一個滿足下述兩條屬性的 m x n 整數矩陣&#xff1a; 每行中的整數從左到右按非嚴格遞增…

六西格瑪綠帶培訓:解鎖質量工程師的職場新篇章

在質量管理這條道路上&#xff0c;我們或許都曾有過這樣的疑問&#xff1a;為何付出了同樣的努力&#xff0c;卻未能獲得預期的回報&#xff1f;當我們看到身邊的同行們逐漸步入高薪的行列&#xff0c;而自己卻似乎陷入了職業的泥沼&#xff0c;這種對比無疑令人倍感焦慮。然而…

了解等保測評的中間件安全Tomcat,如何檢查配置是否符合安全要求?

在等保測評中&#xff0c;Tomcat中間件的安全性是一個重要的評估內容。Tomcat是一個開源的應用服務器&#xff0c;廣泛應用于Web應用程序的開發和部署。由于其易用性和靈活性&#xff0c;Tomcat成為了一個受歡迎的目標&#xff0c;被黑客攻擊和濫用。因此&#xff0c;保證Tomca…

算法提高之信使

算法提高之信使 核心思想&#xff1a;單源最短路 因為數據范圍很小 可以考慮floyd算法(三重循環) #include <iostream>#include <cstring>#include <algorithm>using namespace std;const int N 110,INF 0x3f3f3f3f;int d[N][N];int n,m;int main(){cin…