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