學校網(wǎng)站建設調(diào)研報告天津疫情最新情況
目錄
lambda表達式的概念
lambda表達式語法
lambda表達式的書寫格式
捕捉列表
參數(shù)列表
mutable
返回值類型
函數(shù)體
lambda表達式交換兩個數(shù)
函數(shù)對象與lambda表達式
lambda表達式的概念
????????lambda表達式是一個匿名函數(shù)?它能讓代碼更加地簡潔 提高了代碼可讀性
首先定義一個商品類
struct Goods
{string _name; // 名字double _price; // 價格int _evaluate; // 評價Goods(const char* str, double price, int evaluate):_name(str), _price(price), _evaluate(evaluate){}
};
假設我們要對這些商品進行排序
- 如果要對于一個數(shù)據(jù)集合中的元素進行排序 我們可以使用sort函數(shù) 但是因為這里待排序的是一個結構體 所以我們要自行定義一個比較規(guī)則
- 要控制sort函數(shù)的比較方式有兩種方式:一種是重載商品類的()運算符,一種是仿函數(shù)
- 但是由于這里需要比較的方式不是唯一的 所以不能重載()運算符 只能使用仿函數(shù)
下面是幾種仿函數(shù)
struct ComparePriceLess
{bool operator()(const Goods& g1, const Goods& g2){return g1._price < g2._price;}
};struct ComparePriceGreater
{bool operator()(const Goods& g1, const Goods& g2){return g1._price > g2._price;}
};struct CompareNumLess
{bool operator()(const Goods& g1, const Goods& g2){return g1._num < g2._num;}
};struct CompareNumGreater
{bool operator()(const Goods& g1, const Goods& g2){return g1._num > g2._num;}
};
之后我們?nèi)绻褂胹ort函數(shù)直接使用仿函數(shù)的匿名對象就可以
vector<Goods> v = { { "蘋果", 2.1, 300 }, { "香蕉", 3.3, 100 }, { "橙子", 2.2, 1000 }, { "菠蘿", 1.5, 1 } };sort(v.begin(), v.end(), ComparePriceLess()); // 按價格升序排序 這里的ComparePriceLess()其實是一種匿名對象
sort(v.begin(), v.end(), ComparePriceGreater()); //按價格降序排序
sort(v.begin(), v.end(), CompareNumLess()); //按數(shù)量升序排序
sort(v.begin(), v.end(), CompareNumGreater()); //按數(shù)量降序排序
雖然仿函數(shù)確實能夠解決這里的問題 但是它具有以下問題
- 在一般的類中成員變量都是私有的 如果我們想使用仿函數(shù)進行成員變量之間的比較要聲明友元函數(shù)
- 仿函數(shù)的命名要是不具有可讀性我們就很難理解是按照什么比較的
關于第二點問題的解決 我們這里提出一種新的解決方案 lambda表達式
lambda表達式語法
lambda表達式的書寫格式
[capture-list](parameters)mutable->return-type{statement}
上面的代碼可以修改成:
int main()
{vector<Goods> v = { { "蘋果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2, 3 }, { "菠蘿", 1.5, 4 } };//auto priceLess = [](const Goods& g1, const Goods& g2){return g1._price < g2._price; };//sort(v.begin(), v.end(), priceLess);sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){return g1._price < g2._price; });sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){return g1._price > g2._price; });sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){return g1._evaluate < g2._evaluate; });sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){return g1._evaluate > g2._evaluate; });
}
捕捉列表
[capture-list]
????????該列表總是出現(xiàn)在lambda函數(shù)的最前面 它的作用跟main函數(shù)類似 編譯器根據(jù)它的位置來判斷下面的代碼是否為lamdba函數(shù) 捕捉列表能夠捕捉上下文中的變量供lambda函數(shù)使用
參數(shù)列表
(parameters)
????????與普通函數(shù)的參數(shù)列表使用方式一致 如果沒有參數(shù)需要傳遞可以連同小括號一起省略
mutable
mutable
????????默認情況下 lambda函數(shù)總是一個const函數(shù) mutable可以取消其常屬性 使用該修飾符時 參數(shù)列表不可省略(即使參數(shù)為空)
返回值類型
->return-type
- ? ?用追蹤返回類型形式聲明函數(shù)的返回值類型 沒有返回值時此部分可以省略
- ? ?返回值類型明確情況下也可省略 由編譯器對返回類型進行推導
函數(shù)體
{statement}
函數(shù)體內(nèi)就是要寫函數(shù)的主體?除了可以使用其參數(shù)外 還可以使用所有捕獲到的變量
lambda函數(shù)的參數(shù)列表和返回值類型都是可選部分 但捕捉列表和函數(shù)體是不可省略的 因此最簡單的lambda函數(shù)如下:
int main()
{[]{}; //最簡單的lambda表達式return 0;
}
捕獲列表說明
捕獲列表描述了上下文中哪些數(shù)據(jù)可以被lambda函數(shù)使用 以及使用的方式是傳值還是傳引用
- [var]:表示值傳遞方式捕捉變量var
- [=]:表示值傳遞方式捕獲所有父作用域中的變量(成員函數(shù)包括this指針)
- [&var]:表示引用傳遞捕捉變量var
- [&]:表示引用傳遞捕捉所有父作用域中的變量(成員函數(shù)包括this指針)
- [this]:表示值傳遞方式捕捉當前的this指針
這里對于捕捉列表的一些名詞概念予以說明
- 父作用域指的是包含lambda函數(shù)的語句塊
- 語法上捕捉列表可由多個捕捉項組成 并以逗號分割 比如[=, &a, &b]
- 捕捉列表不允許變量重復傳遞 否則會導致編譯錯誤 比如[=, a]重復傳遞了變量a
- 在塊作用域以外的lambda函數(shù)捕捉列表必須為空 即全局lambda函數(shù)的捕捉列表必須為空
- 在塊作用域中的lambda函數(shù)僅能捕捉父作用域中的局部變量 捕捉任何非此作用域或者非局部變量都會導致編譯報錯
- lambda表達式之間不能相互賦值 即使看起來類型相同
lambda表達式交換兩個數(shù)
傳統(tǒng)寫法
int a = 10;
int b = 20;auto swap = [](int& x, int& y)->void{int z = x;x = y;y = z;
};swap(a, b);
- 因為lambda表達式是一種匿名函數(shù) 所以無法直接調(diào)用 如果想要調(diào)用 我們可以借助auto關鍵字將其賦值給一個變量 用該變量來實現(xiàn)功能
- lambda表達式的函數(shù)體最后還有一個分號
捕獲列表的使用
以引用的方式捕捉所有父作用域中的變量 省略參數(shù)列表和返回值類型?
int a = 10;
int b = 20;auto swap = [&a, &b] // (使用& 捕獲所有參數(shù) 也可以)
{int z = a;a = b;b = z;
};swap(); // 我們這里還必須要調(diào)用以下這個函數(shù)才會使用
傳值捕捉
我們的lambda函數(shù)默認是具有常屬性的 它不會修改內(nèi)部對象的值
所以要先使用mutable關鍵字省略其常屬性 但是省略了這個屬性之后參數(shù)列表就不能省略
int a = 10;
int b = 20;auto swap = [=]()mutable{int z = a;a = b;b = z;
};swap();
但是傳值傳遞本質(zhì)上是對于原始數(shù)據(jù)的一份臨時拷貝 它的修改并不會改變原始的數(shù)據(jù) 所以調(diào)用了swap函數(shù)也不會發(fā)生變化
在全局中不能捕捉對象
int a = 0, b = 1;
//在全局中不能捕捉對象
//auto func5 = [a, b](){};
auto func5 = [](){};
如果用了就會報錯
?
函數(shù)對象與lambda表達式
class Rate
{
public:Rate(double rate): _rate(rate){}double operator()(double money, int year){ return money * _rate * year;}private:double _rate;
};int main()
{// 函數(shù)對象double rate = 1.34;Rate r1(rate);r1(10000, 2);// lambdaauto r2 = [=](double monty, int year)->double{return monty*rate*year; };r2(10000, 2);return 0;
}