微信api文檔徐州seo代理計費
目錄
前言
一、lambda表達式
二、lambda表達式語法
2.1. lambda表達式各部分說明
2.2. 捕獲列表說明
三、函數(shù)對象與lambda表達式
前言
在C++98中,如果想要對一個數(shù)據(jù)集合中的元素進行排序,可以使用std::sort方法。
#include <algorithm>
#include <functional>
int main()
{int array[] = { 4,1,8,5,3,7,0,9,2,6 };// 默認按照小于比較,排出來結(jié)果是升序std::sort(array, array + sizeof(array) / sizeof(array[0]));// 如果需要降序,需要改變元素的比較規(guī)則std::sort(array, array + sizeof(array) / sizeof(array[0]), greater<int>());return 0;
}
如果待排序元素為自定義類型,需要用戶定義排序時的比較規(guī)則:
struct Goods
{string _name;double _price;
};
struct Compare
{bool operator()(const Goods& gl, const Goods& gr){return gl._price <= gr._price;}
};
int main()
{Goods gds[] = { { "蘋果", 2.1 }, { "相交", 3 }, { "橙子", 2.2 }, {"菠蘿", 1.5} };sort(gds, gds + sizeof(gds) / sizeof(gds[0]), Compare());return 0;
}
隨著C++語法的發(fā)展,人們開始覺得上面的寫法太復雜了,每次為了實現(xiàn)一個algorithm算法, 都要重新去寫一個類,如果每次比較的邏輯不一樣,還要去實現(xiàn)多個類,特別是相同類的命名,這些都給編程者帶來了極大的不便。因此,在C11語法中出現(xiàn)了Lambda表達式。
一、lambda表達式
int main()
{Goods gds[] = { { "蘋果", 2.1 }, { "相交", 3 }, { "橙子", 2.2 }, {"菠蘿", 1.5} };sort(gds, gds + sizeof(gds) / sizeof(gds[0]), [](const Goods& l, const Goods& r)->bool{return l._price < r._price;});return 0;
}
上述代碼就是使用C++11中的lambda表達式來解決,可以看出lamb表達式實際是一個匿名函數(shù)。
?
二、lambda表達式語法
lambda表達式書寫格式:[capture-list] (parameters) mutable -> return-type { statement }
2.1. lambda表達式各部分說明
?
[capture-list] : 捕捉列表,該列表總是出現(xiàn)在lambda函數(shù)的開始位置,編譯器根據(jù)[]來判斷接下來的代碼是否為lambda函數(shù),捕捉列表能夠捕捉上下文中的變量供lambda函數(shù)使用。
(parameters):參數(shù)列表。與普通函數(shù)的參數(shù)列表一致,如果不需要參數(shù)傳遞,則可以連同()一起省略
mutable:默認情況下,lambda函數(shù)總是一個const函數(shù),mutable可以取消其常量性。使用該修飾符時,參數(shù)列表不可省略(即使參數(shù)為空)。
->returntype:返回值類型。用追蹤返回類型形式聲明函數(shù)的返回值類型,沒有返回值時此部分可省略。返回值類型明確情況下,也可省略,由編譯器對返回類型進行推導。
{statement}:函數(shù)體。在該函數(shù)體內(nèi),除了可以使用其參數(shù)外,還可以使用所有捕獲到的變量。
注意: 在lambda函數(shù)定義中,參數(shù)列表和返回值類型都是可選部分,而捕捉列表和函數(shù)體可以為空。因此C++11中最簡單的lambda函數(shù)為:[]{}; 該lambda函數(shù)不能做任何事情。
int main()
{// 最簡單的lambda表達式, 該lambda表達式?jīng)]有任何意義[] {};// 省略參數(shù)列表和返回值類型,返回值類型由編譯器推導為intint a = 3, b = 4;[=] {return a + 3; };// 省略了返回值類型,無返回值類型auto fun1 = [&](int c) {b = a + c; };fun1(10)cout << a << " " << b << endl;// 各部分都很完善的lambda函數(shù)auto fun2 = [=, &b](int c)->int {return b += a + c; };cout << fun2(10) << endl;// 復制捕捉xint x = 10;auto add_x = [x](int a) mutable { x *= 2; return a + x; };cout << add_x(10) << endl;return 0;
}
通過上述例子可以看出,lambda表達式實際上可以理解為無名函數(shù),該函數(shù)無法直接調(diào)用,如果想要直接調(diào)用,可借助auto將其賦值給一個變量。
?
2.2. 捕獲列表說明
捕捉列表描述了上下文中那些數(shù)據(jù)可以被lambda使用,以及使用的方式傳值還是傳引用。
[var]:表示值傳遞方式捕捉變量var
[=]:表示值傳遞方式捕獲所有父作用域中的變量(包括this)
[&var]:表示引用傳遞捕捉變量var
[&]:表示引用傳遞捕捉所有父作用域中的變量(包括this)
[this]:表示值傳遞方式捕捉當前的this指針
注意:
a. 父作用域指包含lambda函數(shù)的語句塊
b. 語法上捕捉列表可由多個捕捉項組成,并以逗號分割
比如:[=, &a, &b]:以引用傳遞的方式捕捉變量a和b,值傳遞方式捕捉其他所有變量 [&,a, this]:值傳遞方式捕捉變量a和this,引用方式捕捉其他變量 c. 捕捉列表不允許變量重復傳遞,否則就會導致編譯錯誤。 比如:[=, a]:=已經(jīng)以值傳遞方式捕捉了所有變量,捕捉a重
復
d. 在塊作用域以外的lambda函數(shù)捕捉列表必須為空。
e. 在塊作用域中的lambda函數(shù)僅能捕捉父作用域中局部變量,捕捉任何非此作用域或者非局部變量都會導致編譯報錯。
f. lambda表達式之間不能相互賦值,即使看起來類型相同
void (*PF)();
int main()
{auto f1 = [] {cout << "hello world" << endl; };auto f2 = [] {cout << "hello world" << endl; };// 此處先不解釋原因,等lambda表達式底層實現(xiàn)原理看完后,大家就清楚了//f1 = f2; // 編譯失敗--->提示找不到operator=()// 允許使用一個lambda表達式拷貝構(gòu)造一個新的副本auto f3(f2);f3();// 可以將lambda表達式賦值給相同類型的函數(shù)指針PF = f2;PF();return 0;
}
三、函數(shù)對象與lambda表達式
函數(shù)對象,又稱為仿函數(shù),即可以想函數(shù)一樣使用的對象,就是在類中重載了operator()運算符的類對象。
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 = 0.49;Rate r1(rate);r1(10000, 2);// lamberauto r2 = [=](double monty, int year)->double {return monty * rate * year; };r2(10000, 2);return 0;
}
從使用方式上來看,函數(shù)對象與lambda表達式完全一樣。
函數(shù)對象將rate作為其成員變量,在定義對象時給出初始值即可,lambda表達式通過捕獲列表可以直接將該變量捕獲到
實際在底層編譯器對于lambda表達式的處理方式,完全就是按照函數(shù)對象的方式處理的,即:如果定義了一個lambda表達式,編譯器會自動生成一個類,在該類中重載了operator()。