C++ 中的Lambda 運算式

文章推薦指數: 80 %
投票人數:10人

ISO C++ 標準顯示將傳遞為 std::sort() 函式第三個引數的簡單Lambda: ... that shows how to use lambda expressions with class member functions, ... 跳到主要內容 已不再支援此瀏覽器。

請升級至MicrosoftEdge,以利用最新功能、安全性更新和技術支援。

下載MicrosoftEdge 其他資訊 目錄 結束焦點模式 語言 閱讀英文 儲存 目錄 閱讀英文 儲存 Twitter LinkedIn Facebook 電子郵件 目錄 C++中的Lambda運算式 發行項 05/04/2022 8位參與者 本文內容 在C++11和更新版本中,Lambda運算式通常稱為Lambda,是定義匿名函式物件的便利方式,(關閉)直接在叫用或傳遞為函式引數的位置。

通常Lambda是用來封裝幾行程式碼,這些程式碼會傳遞至演算法或非同步函式。

本文會定義什麼是Lambda,並將其與其他程式設計技術進行比較。

它會描述其優點,並提供一些基本範例。

相關文章 Lambda運算式與函式物件 使用Lambda運算式 constexprLambda運算式 Lambda運算式的元件 ISOC++標準顯示將傳遞為std::sort()函式第三個引數的簡單Lambda: #include #include voidabssort(float*x,unsignedn){ std::sort(x,x+n, //Lambdaexpressionbegins [](floata,floatb){ return(std::abs(a)<:abs capture exception-specification trailing-return-type lambda structs voids::f template> voidf(Args...args){ autox=[args...]{returng(args...);}; x(); } 若要在類別成員函式主體中使用Lambda運算式,請將this指標傳遞至capture子句,以提供封入類別成員函式和資料成員的存取權。

VisualStudio201715.3版和更新版本(/std:c++17模式和更新版本):this在擷取子句中指定*this,即可依值擷取指標。

依值擷取會將整個關閉複製到叫用Lambda的每個呼叫月臺。

(關閉是匿名函式物件,可封裝Lambdaexpression.)當Lambda以平行或非同步作業執行時,依值擷取會很有用。

它特別適用于某些硬體架構,例如NUMA。

Foranexamplethatshowshowtouselambdaexpressionswithclassmemberfunctions,see"Example:Usingalambdaexpressioninamethod"inExamplesoflambdaexpressions. 當您使用擷取子句時,建議您記住這些點,特別是當您搭配多執行緒使用Lambda時: 參考擷取可用來修改外部的變數,但無法擷取值。

(mutable允許修改複本,但不允許originals.) 參考擷取會反映外部變數的更新,但值擷取不會。

傳址擷取方式採用存留期相依性,但傳值擷取方式沒有存留期相依性。

當Lambda以非同步方式執行時,特別重要。

如果您在非同步Lambda中依參考方式擷取本機,該本機可能會在Lambda執行時輕鬆消失。

您的程式碼可能會在執行時間造成存取違規。

一般化擷取(C++14) 在C++14,您可以在擷取子句中引進並初始化新的變數,而這些變數不需要存在於Lambda函式的封閉範圍中。

初始化可以表示為任何任意運算式;新變數的類型是透過運算式所產生的類型推斷而來。

此功能可讓您擷取僅限移動變數(,例如std::unique_ptr從周圍範圍),並在Lambda中使用它們。

pNums=make_unique>(nums); //... autoa=[ptr=move(pNums)]() { //useptr }; 參數清單 Lambda可以同時擷取變數並接受輸入參數。

標準語法中的參數清單(Lambda宣告子是選擇性)的,而且在大部分方面類似于函式的參數清單。

autoy=[](intfirst,intsecond) { returnfirst+second; }; 在C++14中,如果參數類型為泛型,您可以使用auto關鍵字作為類型規範。

此關鍵字會告訴編譯器建立函式呼叫運算子作為範本。

參數清單中的每個實例auto都相當於相異的類型參數。

autoy=[](autofirst,autosecond) { returnfirst+second; }; Lambda運算式可接受另一個Lambda運算式當做其引數。

Formoreinformation,see"Higher-OrderLambdaExpressions"inthearticleExamplesoflambdaexpressions. 因為參數清單是選擇性的,如果您未將引數傳遞至Lambda運算式,且其Lambda宣告子不包含例外狀況規格、尾端傳回型別或mutable,則可以省略空括弧。

可變動規格 一般而言,Lambda的函式呼叫運算子是const-by-value,但使用關鍵字會mutable取消此動作。

它不會產生可變動的資料成員。

規格mutable可讓Lambda運算式的主體修改依值擷取的變數。

本文稍後的一些範例示範如何使用mutable。

例外狀況規格 您可以使用noexcept例外狀況規格來指出Lambda運算式不會擲回任何例外狀況。

如同一般函式,如果Lambda運算式宣告noexcept例外狀況規格,且Lambda主體擲回例外狀況,MicrosoftC++編譯器會產生警告C4297,如下所示: //throw_lambda_expression.cpp //compilewith:/W4/EHsc intmain()//C4297expected { []()noexcept{throw5;}(); } 如需詳細資訊,請參閱例外狀況規格(擲回)。

傳回類型 Lambda運算式的傳回型別會自動推算出來。

除非您指定尾端傳回類型,auto否則不需要使用關鍵字。

尾端傳回類型類似于一般函式或成員函式的傳回類型部分。

不過,傳回型別必須接在參數清單後面,而且您必須在傳回型別前面包含trailing-return-type關鍵字->。

如果Lambda主體只包含一個return語句,則可以省略Lambda運算式的傳回類型部分。

或者,如果運算式未傳回值,則為。

如果Lambda主體包含單一return陳述式,編譯器會從傳回運算式的類型推算傳回型別。

否則,編譯器會將傳回型別推斷為void。

請考慮下列說明此準則的範例程式碼片段: autox1=[](inti){returni;};//OK:returntypeisint autox2=[]{return{1,2};};//ERROR:returntypeisvoid,deducing //returntypefrombraced-init-listisn'tvalid Lambda運算式可能會產生另一個Lambda運算式當做其傳回值。

Formoreinformation,see"Higher-orderlambdaexpressions"inExamplesoflambdaexpressions. Lambda主體 Lambda運算式的Lambda主體是複合陳述式。

它可以包含一般函式或成員函式主體中允許的任何專案。

一般函式和Lambda運算式的主體都可以存取下列類型的變數: 擷取自封閉範圍的變數(如先前所述)。

參數。

本機宣告的變數。

類別資料成員,在類別內宣告且this已擷取時。

任何具有靜態儲存持續時間的變數,例如全域變數。

下列範例包含Lambda運算式,這個運算式會以傳值方式明確擷取變數n,並以傳址方式隱含擷取變數m: //captures_lambda_expression.cpp //compilewith:/W4/EHsc #include usingnamespacestd; intmain() { intm=0; intn=0; [&,n](inta)mutable{m=++n+a;}(4); cout<&v) { //Alocalstaticvariable. staticintnextValue=1; //Thelambdaexpressionthatappearsinthefollowingcallto //thegeneratefunctionmodifiesandusesthelocalstatic //variablenextValue. generate(v.begin(),v.end(),[]{returnnextValue++;}); //WARNING:thisisn'tthread-safeandisshownforillustrationonly } 如需詳細資訊,請參閱generate。

下列程式碼範例會使用上一個範例中的函式,並新增使用C++標準程式庫演算法generate_n的Lambda運算式範例。

此Lambda運算式會將vector物件的元素指派給前兩個元素的總和。

使用mutable關鍵字,讓Lambda運算式的主體可以修改其外部變數x和y的複本,Lambda運算式會依值擷取。

由於Lambda運算式會以傳值方式擷取原始變數x和y,在Lambda執行後,它們的值仍然保持1。

//compilewith:/W4/EHsc #include #include #include #include usingnamespacestd; templatevoidprint(conststring&s,constC&c){ cout<&v) { //Alocalstaticvariable. staticintnextValue=1; //Thelambdaexpressionthatappearsinthefollowingcallto //thegeneratefunctionmodifiesandusesthelocalstatic //variablenextValue. generate(v.begin(),v.end(),[]{returnnextValue++;}); //WARNING:thisisn'tthread-safeandisshownforillustrationonly } intmain() { //Thenumberofelementsinthevector. constintelementCount=9; //Createavectorobjectwitheachelementsetto1. vectorv(elementCount,1); //Thesevariablesholdtheprevioustwoelementsofthevector. intx=1; inty=1; //Setseachelementinthevectortothesumofthe //previoustwoelements. generate_n(v.begin()+2, elementCount-2, [=]()mutablethrow()->int{//lambdaisthe3rdparameter //Generatecurrentvalue. intn=x+y; //Updateprevioustwovalues. x=y; y=n; returnn; }); print("vectorvaftercalltogenerate_n()withlambda:",v); //Printthelocalvariablesxandy. //Thevaluesofxandyholdtheirinitialvaluesbecause //theyarecapturedbyvalue. cout<int{returnt*t;}; 若要判斷Lambda是否支援特定修飾詞,請參閱Microsoft特定修飾詞一節中的修飾詞相關文章。

VisualStudio支援C++11標準Lambda功能和無狀態Lambda。

無狀態Lambda可轉換成使用任意呼叫慣例的函式指標。

另請參閱 C++語言參考 C++標準程式庫中的函式物件 函式呼叫 for_each 本文內容



請為這篇文章評分?