lambda運算式
匿名函式(lambda函式)
匿名函式(英文名:lambda)就是沒有名字的函式,最簡單的匿名函式是[]{},它沒有引數也沒有回傳值,在匿名函式中,[]里面用來捕獲函式外部的變數,而()里面就是匿名函式的引數,{}里面就是函式的執行代碼,
匿名函式也稱lambda函式或lambda運算式
示例:
#include <iostream>
using namespace std;
int main()
{
//定義函式,使用auto來自動獲取function的型別
auto function = [](){ cout << "Hello world!"; };
fuction(); //呼叫函式
return 0;
}
lambda運算式的宣告
lambda運算式完整宣告形式如下:
[capture list](params list)mutable exception->return type{function body}
具體含義如下:
-
capture list:捕獲外部變數串列,總是出現在lambda運算式的起始位置,編譯器根據[]來判斷接下來的代碼是否為lambda運算式
-
params list:形參串列
-
mutable:指示符,用來表示是否可修改捕獲的變數,使用mutable指示符時,引數串列不能省略,即使為空
-
exception:例外設定,用于指定函式拋出的例外,如拋出整數型別的例外,可以使用 throw(int)
-
return type:回傳型別,回傳型別可以省略,但編譯器會推斷出lambda運算式的回傳型別:(1)如果function body中存在return陳述句,則運算式的回傳型別由return陳述句的回傳型別決定;(2)如果function body中沒有return陳述句,則回傳型別為void
-
function body:函式主體
同時,也可以省略其中的某些成分來宣告“不完整”的lambda運算式
常見的幾種如下:
1. [capture list](params list)->return type{function body}
2. [capture list](params list){funtion body}
3. [capture list]{fuction body}
實體:
#include <iostream>
#include <vector>
#include <time.h>
#include <algorithm>
using namespace std;
int main()
{
srand(time(0));
vector<vector<int>> nums(10, vector<int>(2, 0));
for (int i = 0; i < nums.size(); i++)
{
nums[i][0] = i;
nums[i][1] = rand() % 10;
}
sort(nums.begin(), nums.end(), [](vector<int> &a, vector<int> &b) -> bool
{ return a[1] < b[1]; });
for (vector<int> &num : nums)
{
cout << num[0] << '(' << num[1] << ") ";
}
return 0;
}
//結果
//4(2) 5(2) 9(2) 0(5) 8(5) 1(7) 3(7) 7(8) 2(9) 6(9)
使用STL中的sort函式時,可以為其提供一個謂詞函式作為排序的依據,這里使用lambda運算式作為謂詞函式,方便簡潔
lambda運算式具體用法
下面對lambda運算式中各項的具體用法進行介紹
捕獲外部變數
lambda運算式可以使用其可見范圍內的外部變數,但必須宣告哪些外部變數可以被該lambda運算式使用,lambda運算式通過在最前面的方括號[] 來指明內部可以訪問的外部變數,這一程序也稱lambda運算式“捕獲了”外部變數
- 捕獲串列可由多個捕獲項組成,以逗號隔開,需要注意捕獲項不能重復,否則會編譯錯誤,比如[=,num],=已經捕獲過num了
- 只能捕獲當前作用域的區域變數,捕獲作用域外的區域變數或非區域變數都會報錯
- lambda運算式之間不能賦值
類似引數傳遞方式(值傳遞、參考傳遞、指標傳遞),在lambda運算式中,外部變數的捕獲方式也有值捕獲、參考捕獲、隱式捕獲
1. 值捕獲
值捕獲與引數傳遞中的值傳遞類似,被捕獲的變數在lambda運算式創建時通過值拷貝的方式傳入,隨后對該變數的修改不會影響lambda運算式
需要注意,以值捕獲外部變數,在lambda運算式函式體中不能對該外部變數的值進行修改,即值捕獲具有常性
示例:
#include <iostream>
using namespace std;
int main()
{
int num = 17;
auto func = [num]{cout << num << endl;};
num = 19;
func();
return 0;
}
//結果
//17
這個例子中lambda運算式在創建時捕獲了num變數,并在創建后在外部對num的值進行了修改,在使用lambda運算式時輸出的仍是num的初始值,體現了lambda運算式是在創建時獲得了num變數的值
2. 參考捕獲
使用參考捕獲一個外部變數,只需在捕獲變數前加上一個參考說明符&,參考捕獲不具有常性
示例:
#include <iostream>
using namespace std;
int main()
{
int num = 17;
auto func = [&num]{cout << num << endl;};
num = 19;
func();
return 0;
}
//結果
//19
3. 隱式捕獲
值捕獲和參考捕獲都需要我們在捕獲串列中顯示地列出lambda運算式中使用的外部變數,
此外,我們還可以讓編譯器根據函式體中的代碼來推斷需要捕獲哪些外部變數,這種方式稱為隱式捕獲,隱式捕獲有兩種方式,分別是[=]和[&],[=]表示以值捕獲,[&]表示以參考捕獲
隱式值捕獲示例:
#include <iostream>
using namespace std;
int main()
{
int num1 = 17 , num2 = 21;
auto func = [=]{cout << num1 << ',' << num2 << endl;};
num1 = 19;
num2 = 27;
func();
return 0;
}
//結果
//17,21
隱式參考捕獲示例:
#include <iostream>
using namespace std;
int main()
{
int num1 = 17 , num2 = 21;
auto func = [&]{cout << num1 << ',' << num2 << endl;};
num1 = 19;
num2 = 27;
func();
return 0;
}
//結果
//19,27
4. 混合方式
上面的例子,要么是值捕獲,要么是參考捕獲,Lambda運算式還支持混合的方式捕獲外部變數,這種方式主要是以上幾種捕獲方式的組合使用,
示例:
#include <iostream>
using namespace std;
#define p 12
int main()
{
int num1 = 17 , num2 = 21;
auto func = [num1,&num2](){cout << num1 << ',' << num2 << endl;};
num1 = 19;
num2 = 27;
func();
return 0;
}
//結果
//17,27
C++11中的lambda運算式捕獲外部變數的主要形式
| 捕獲形式 | 具體說明 |
|---|---|
| [] | 不捕獲任何外部變數 |
| [變數名,...] | 默認以值捕獲指定的多個變數,如果參考捕獲,需顯示宣告(&) |
| [this] | 以值捕獲this指標 |
| [=] | 以值捕獲所有需要的外部變數,包括this指標 |
| [&] | 以參考捕獲所有需要的外部變數,包括this指標 |
| [=,&num1,&num2] | 以參考捕獲變數num1、num2,其余變數以值捕獲 |
| [&,num1,num2] | 以值捕獲變數num1、num2,其余變數以參考捕獲 |
mutable指示符——修改捕獲變數
前面有提到,在lambda運算式中,如果以值傳遞捕獲外部變數,則函式體中不能修改該外部變數,否則會編譯錯誤
通過使用mutable關鍵字,用以說明運算式的函式體可以修改值捕獲的變數
示例:
#include <iostream>
using namespace std;
int main()
{
int num1 = 17 , num2 = 21;
auto func = [=]()mutable{cout << ++num1 << ',' << ++num2 << endl;};
num1 = 19;
num2 = 27;
func();
return 0;
}
//結果
//18,22
lambda運算式的引數串列
lambda運算式的引數與普通函式的引數類似,但在lambda運算式中傳遞引數存在著一些限制,主要有以下幾點
- 引數串列中不能有默認引數
- 不支持可變引數
- 所有引數必須有引數名
lambda運算式的原理
實際上編譯器在全域作用域自動生成了一個類,在類中多載了operator(),operator()函式的內容就是lambda運算式的內容,
故可以理解為lambda運算式本質上還是仿函式,是一個編譯器自動生成的仿函式,
lambda運算式與STL
lambda運算式的引入為STL的使用帶來了極大的便利,我們可以在泛型演算法中提供lambda運算式作為謂詞函式進行某些操作
示例(統計元素和):
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector<int> nums{1, 2, 3, 4, 5, 6, 7, 8, 9};
int sum = 0;
for_each(nums.begin(), nums.end(), [&sum](int val)
{ sum += val; });
cout << sum << endl;
return 0;
}
//結果
//45
本文來自博客園,作者:Vergissmeinnicht_z,轉載請注明原文鏈接:https://www.cnblogs.com/Vergissmeinnicht-rj/p/17059580.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/542195.html
標籤:其他
上一篇:Python匯入Excel表格資料并以字典dict格式保存
下一篇:字符編碼
