作者:李春港
出處:https://www.cnblogs.com/lcgbk/p/14088462.html
- 一、前言
- 二、Lambda運算式格式說明
- 2.1 完整的Lambda運算式格式
- 2.2 常見的Lambda運算式格式
- 2.3 lambda 運算式捕獲串列
- 三、示例
- 3.1 STL的sort函式引數使用Lambda
- 3.2 有回傳值的Lambda運算式
- 3.3 無引數Lambda運算式
- 3.4 捕獲外部變數的Lambda運算式
一、前言
由于前段時間在閱讀一些C++原始碼的時候發現了Lambda運算式,所以在此也記錄下Lambda運算式的使用,
很早之前Lambda在很多高級語言中,就已經被廣泛地使用了,在一個程式中Lambda運算式可以理解為是匿名函式,在C++中,到了C++11標準才引入了這個Lambda運算式,這是C++11最重要而且也是最常用的特性之一,
使用Lambda運算式,不需要額外地定義函式名,可以更直接撰寫程式,有比較好的可讀性和可維護性;不需要另外宣告和定義函式體,避免了程式代碼的膨脹,
二、Lambda運算式格式說明
2.1 完整的Lambda運算式格式
[capture list] (params list) mutable exception-> return type { function body }
說明:
| 名稱 | 決議 |
|---|---|
| [capture list] | 捕獲串列:lambda 運算式可以通過捕獲串列捕獲一定范圍內的變數, |
| (params list) | 形參串列,用于傳參(可以省略), |
| mutable | 用來說明是否可以修改按值捕獲的變數(可以省略),如果需要修改按值捕獲的變數,則需要添加, |
| exception | 例外設定(可以省略), |
| return type | 回傳型別 (可省略,如果省略則自動從函式體中判斷回傳型別,return后的值,如果沒有則回傳void), |
| function body | 函式體,即邏輯代碼, |
2.2 常見的Lambda運算式格式
| 編號 | 格式 | 特性 |
|---|---|---|
| 格式1 | [capture list] (params list) -> return type {function body} | 1、無法修改捕獲串列中的變數值, |
| 格式2 | [capture list] (params list) {function body} | 1、無法修改捕獲串列中的變數值;2、回傳型別由return回傳的值型別確定,如果沒有return陳述句,則回傳型別為void, |
| 格式3 | [capture list] {function body} | 1、無法修改捕獲串列中的變數值;2、回傳型別由return回傳的值型別確定,如果沒有return陳述句,則回傳型別為void;3、不能傳入引數,類似普通的無參函式, |
2.3 lambda 運算式捕獲串列
| 捕獲形式 | 決議 |
|---|---|
| [ ] | 不捕獲任何變數, |
| [&] | 捕獲外部作用域中所有變數,并作為參考在函式體中使用(按參考捕獲), |
| [=] | 捕獲外部作用域中所有變數,并作為副本在函式體中使用(按值捕獲), |
| [=,&x] | 按值捕獲外部作用域中所有變數,并按參考捕獲 x 變數, |
| [x] | 按值捕獲 x 變數,同時不捕獲其他變數, |
| [this] | 捕獲當前類中的 this 指標,讓 lambda 運算式擁有和當前類成員函式同樣的訪問權限,如果已經使用了 & 或者 =,就默認添加此選項, |
注意:
- 如果是按值捕獲,那么是否可以改變捕獲的變數值,取決于mutable關鍵字,
三、示例
3.1 STL的sort函式引數使用Lambda
/*****************************************************************************
** Copyright ? 2020 lcg. All rights reserved.
** File name: Lambda.cpp
** Description: 在STL的sort函式引數使用Lambda運算式
** Author: lcg
** Version: 1.0
** Date: 2020.12.04
*****************************************************************************/
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool cmp(int a, int b)
{
return a < b;
}
int main()
{
vector<int> vec{ 3, 2, 5, 7, 3, 2 };
vector<int> lbvec(vec);
/**1、不使用Lambda運算式的寫法**/
sort(vec.begin(), vec.end(), cmp);
cout << "predicate function:" << endl;
for (int it : vec) // 此for回圈寫法也是在C++11才出現
cout << it << ' ';
cout << endl;
/**2、使用Lambda運算式的寫法**/
sort(lbvec.begin(), lbvec.end(), [](int a, int b) -> bool { return a < b; });
cout << "lambda expression:" << endl;
for (int it : lbvec)
cout << it << ' ';
}
可以看到這種情況使用Lambda運算式可以使代碼更加直觀、簡介,無需再定義 cmp(int a, int b) 函式,
3.2 有回傳值的Lambda運算式
/** 1、標明回傳型別**/
auto f = [](int a) -> int { return a + 1; };
std::cout << f(1) << std::endl; /**輸出: 2**/
/** 2、無標明回傳型別**/
auto f = [](int a) { return a + 1; };
std::cout << f(1) << std::endl; /**輸出: 2**/
當沒有標明回傳型別的時候,系統會根據return回來的值來判斷回傳值的型別,auto會自動檢索回傳值的型別,
3.3 無引數Lambda運算式
auto f = []() { return 1; };
std::cout << f() << std::endl; /**輸出: 1**/
3.4 捕獲外部變數的Lambda運算式
/*****************************************************************************
** Copyright ? 2020 lcg. All rights reserved.
** File name: Lambda.cpp
** Description: 捕獲外部變數的Lambda運算式
** Author: lcg
** Version: 1.0
** Date: 2020.12.04
*****************************************************************************/
#include <iostream>
class A
{
public:
int i_ = 0;
void func(int x, int y)
{
/* error,沒有捕獲外部變數*/
auto x1 = []{ return i_; };
/*OK,按值捕獲所有外部變數,包括了this指標*/
auto x2 = [=]{ return i_ + x + y; };
/*OK,按參考捕獲所有外部變數,包括了this指標*/
auto x3 = [&]{ return i_ + x + y; };
/*OK,捕獲this指標,Lambda擁有和此類中普通函式一樣的權限*/
auto x4 = [this]{ return i_; };
/*error,沒有捕獲x、y,因為x、y變數不屬于this*/
auto x5 = [this]{ return i_ + x + y; };
/* OK,捕獲this指標、x、y*/
auto x6 = [this, x, y]{ return i_ + x + y; };
/*OK,捕獲this指標,并修改成員的值*/
auto x7 = [this]{ return i_=7; };
x7();
std::cout<<i_<<std::endl;//輸出7
/*OK,捕獲所有外部變數,默認捕獲this指標,并修改成員的值*/
auto x8 = [=]{ return i_=8; };
x8();
std::cout<<i_<<std::endl;//輸出8
/*error,因為i_不屬于捕獲范圍的變數,所以無法按值捕獲i_變數,可以通過捕獲this指標來獲取i_使用權*/
auto x9 = [i_]{ return i_++; };
/*error,原因同上*/
auto x10 = [&i_]{ return i_++; };
/*ok,按參考捕獲所有變數,默認捕獲this指標,并修改成員的值*/
auto x11 = [&]{ return i_=11; };
x11();
std::cout<<i_<<std::endl;//輸出11
/*error,按值捕獲x變數,并修改值*/
auto x12 = [x]{ return x++; };
/*ok,按值捕獲x變數,并修改值*/
auto x13 = [x]()mutable{ return x=13; };
x13();
std::cout<<x<<std::endl;//輸出1
/*ok,按參考捕獲x變數,并修改值*/
auto x14 = [&x]{ return x=14; };
x14();
std::cout<<x<<std::endl;//輸出14
}
};
int main(int argc, char *argv[])
{
A l;
l.func(1,2);
int a = 0, b = 1;
/*error,沒有捕獲外部變數*/
auto f1 = []{ return a; };
/*OK,捕獲所有外部變數,改變a值*/
auto f2 = [&]{ return a=2; };
f2();
std::cout<<a<<std::endl;//輸出2
/*OK,捕獲所有外部變數,并回傳a*/
auto f3 = [=]{ return a; };
/*error,a是以復制方式捕獲的,無法修改*/
auto f4 = [=]{ return a=4; };
/*ok,a是以復制方式捕獲的,修改a值*/
auto f4 = [=]()mutable{ return a=4; };
f4();
std::cout<<a<<std::endl;//輸出2
/*error,沒有捕獲變數b*/
auto f5 = [a]{ return a + b; };
/*OK,捕獲a和b的參考,并對b做自加運算*/
auto f6 = [a, &b]{ return a + (b++); };
/*OK,捕獲所有外部變數和b的參考,并對b做自加運算*/
auto f7 = [=, &b]{ return a + (b++); };
return 0;
}
總結:
- 當按值的方式獲取外部變數時,是無法更改獲取過來的值的,除非使用mutable關鍵字宣告,就可以更改(更改的不是外部變數原本地址里的值,而是lambda函式體內的副本);
- 當按參考的方式捕獲外部變數時,lambda函式體內可以更改此值,更改的是外部變數原本地址里的值;
- 當在類中,lambda運算式捕獲this指標時,lambda函式體內可以直接改變該類中的變數,和類中的普通函式擁有一樣的權限,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/230586.html
標籤:C++
