C++ 中的Lambda 運算式
文章推薦指數: 80 %
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
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
標準語法中的參數清單(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
下列程式碼範例會使用上一個範例中的函式,並新增使用C++標準程式庫演算法generate_n的Lambda運算式範例。
此Lambda運算式會將vector物件的元素指派給前兩個元素的總和。
使用mutable關鍵字,讓Lambda運算式的主體可以修改其外部變數x和y的複本,Lambda運算式會依值擷取。
由於Lambda運算式會以傳值方式擷取原始變數x和y,在Lambda執行後,它們的值仍然保持1。
//compilewith:/W4/EHsc
#include&v)
{
//Alocalstaticvariable.
staticintnextValue=1;
//Thelambdaexpressionthatappearsinthefollowingcallto
//thegeneratefunctionmodifiesandusesthelocalstatic
//variablenextValue.
generate(v.begin(),v.end(),[]{returnnextValue++;});
//WARNING:thisisn'tthread-safeandisshownforillustrationonly
}
intmain()
{
//Thenumberofelementsinthevector.
constintelementCount=9;
//Createavectorobjectwitheachelementsetto1.
vector
VisualStudio支援C++11標準Lambda功能和無狀態Lambda。
無狀態Lambda可轉換成使用任意呼叫慣例的函式指標。
另請參閱
C++語言參考
C++標準程式庫中的函式物件
函式呼叫
for_each
本文內容
延伸文章資訊
- 1Lambda Expressions vs Function Pointers - GeeksforGeeks
A Lambda expression is also called an anonymous function. It is an expression contained within th...
- 2C++ 中的Lambda 運算式
ISO C++ 標準顯示將傳遞為 std::sort() 函式第三個引數的簡單Lambda: ... that shows how to use lambda expressions with ...
- 3In C++, what is the reasoning behind not allowing function ...
I'm not a C++ programmer, but wouldn't that cause loss of information? I mean, the lambda also ha...
- 4C++ Tutorial => Conversion to function pointer
This function pointer is in no way reliant on the source lambda closure's existence. It therefore...
- 5Passing C++ captureless lambda as function pointer to C API