搭建視頻服務(wù)器武漢網(wǎng)站搜索引擎優(yōu)化
一、lambda表達(dá)式
1)、為啥需要引入lambda?
?在c++98中,我們使用sort對(duì)一段自定義類型進(jìn)行排序的時(shí)候,每次都需要傳一個(gè)仿函數(shù),即手寫一個(gè)完整的類。甚至有時(shí)需要同時(shí)實(shí)現(xiàn)排升序和降序,就需要各自手寫一個(gè)類,非常不方便!所以C++11引入了lambda表達(dá)式!
?lamaba是一個(gè)匿名函數(shù)對(duì)象,是一個(gè)可調(diào)用對(duì)象,表達(dá)式本質(zhì)上也是一個(gè)類(vs中類名為lambda_uuid),并實(shí)現(xiàn)了operator()。
【C98玩法】:
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){}
};
struct ComparePriceLess
{bool operator()(const Goods& gl, const Goods& gr){return gl._price < gr._price;}
};
struct ComparePriceGreater
{bool operator()(const Goods& gl, const Goods& gr){return gl._price > gr._price;}
};
int main()
{vector<Goods> v = { { "蘋果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2, 3 }, { "菠蘿", 1.5, 4 } };sort(v.begin(), v.end(), ComparePriceLess());sort(v.begin(), v.end(), ComparePriceGreater());
}
【C++11 lambda表達(dá)式】:
int main()
{vector<Goods> v = { { "蘋果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2, 3 }, { "菠蘿", 1.5, 4 } };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; });
}
2)、lambda表達(dá)式語法
?lambda表達(dá)式書寫格式:[capture-list] (parameters) mutable -> return-type { statement }
- capture-list(捕捉列表):編譯器根據(jù)[ ]來判斷接下來的代碼是否為lambda函數(shù),[ ]可以捕捉父作用域的變量供lambda函數(shù)使用。
- parameters(列表參數(shù)):和普通函數(shù)列表參數(shù)一樣。如果沒用,可以連同()一起省略。
- mutable 默認(rèn)情況下lambda是一個(gè)const函數(shù)(實(shí)際上是用于修飾operator()的),mutable可以取消其常量性。使用該修飾符時(shí),參數(shù)列表不可省略(即使參數(shù)為空)。
- return-type:用于聲明返回值類型。如果沒用返回值可以省略;即使有返回值也可以省略,由編譯器自動(dòng)推導(dǎo)!
- statement 函數(shù)體。在該函數(shù)體內(nèi),除了可以使用其參數(shù)外,還可以使用所有捕獲到的變量。
在lambda函數(shù)定義中,參數(shù)列表和返回值類型都是可選部分,而捕捉列表和函數(shù)體可以為空。因此C++11中最簡單的lambda函數(shù)為:[]{}; 該lambda函數(shù)不能做任何事情。
3)、capture-list(捕捉列表)細(xì)節(jié)
?捕捉列表用于捕捉父作用域中變量供lambda函數(shù)使用,捕捉方分為以下幾種:
- [var]:表示值傳遞方式捕捉變量var。
- [=]:表示傳值方式捕捉父作用域中的所有變量(包括this)。
- [&var]:表示引用傳遞方式捕捉變量var。
- [&]:表示引用方式捕捉父作用域中的所有變量(包括this)。
- [this]:表示值傳遞方式捕捉當(dāng)前的this指針
?除此之外,捕捉列表可以由多個(gè)捕捉項(xiàng)組成,以逗號(hào)分割。比如:
???? [=, &a, &b]:除引用捕捉a、b外,其他父作用域變量傳值捕捉!
???? [&, a, this]:值傳遞方式捕捉變量a和this,引用方式捕捉其他變量。
?并且捕捉列表不能重復(fù)變量傳遞,否則會(huì)導(dǎo)致編譯錯(cuò)誤。比如:[=, a]:a變量傳遞了兩次。lambda表達(dá)式之間不能相互賦值,即使類型相同,但編譯后類名都變?yōu)榱薼ambda_uuid),類名不相同!
4)、函數(shù)對(duì)象與lambda表達(dá)式
?函數(shù)對(duì)象又稱仿函數(shù),既可以像普通函數(shù)一樣使用(在類中重載operator())。而lambda本質(zhì)上一個(gè)一個(gè)函數(shù)對(duì)象,在編譯后會(huì)轉(zhuǎn)化成一個(gè)仿函數(shù),并對(duì)operator()進(jìn)行重載!
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 = 0.49;Rate r1(rate);r1(10000, 2);// lamberauto r2 = [=](double monty, int year)->double {return monty * rate * year;};r2(10000, 2);return 0;
}
【反匯編結(jié)果】:
二、function包裝器
1)、包裝器由來
?function包裝器 也叫作適配器,包裝的是可調(diào)用對(duì)象。C++中的function本質(zhì)是一個(gè)類模板,也是一個(gè)包裝器。
?在C++中有3種可調(diào)用對(duì)象:函數(shù)指針、仿函數(shù)、lambda!但我們發(fā)現(xiàn)想要獲得他們的都存在一些缺陷:函數(shù)指針非常麻煩,類型和對(duì)象嵌在一起;仿函數(shù)很重,即使是一個(gè)很簡單的比較邏輯也要在外面定義一個(gè)類;lambda沒法寫類型,不同的機(jī)器和時(shí)間uuid不同,并且相對(duì)匿名(當(dāng)然decltype可以獲的)
?除此在外,眾多的可調(diào)用對(duì)象類型會(huì)導(dǎo)致模板的效率低下! 原因在于假設(shè)現(xiàn)在存在一個(gè)函數(shù)模板,我需要將一個(gè)可調(diào)用對(duì)象作為模板參數(shù)進(jìn)行傳遞來達(dá)到某種目的。但眾多的可調(diào)用對(duì)象可能實(shí)現(xiàn)的是同一個(gè)功能,但分別傳遞給模板后需要實(shí)例化3份,導(dǎo)致模板效率降低!!所以包裝器對(duì)可調(diào)用對(duì)象進(jìn)行了統(tǒng)一!
【實(shí)例】:
template<class F, class T>
T useF(F f, T x)
{static int count = 0;cout << "count:" << ++count << endl;cout << "count:" << &count << endl;return f(x);
}
double f(double i)
{return i / 2;
}
struct Functor
{double operator()(double d){return d / 3;}
};
int main()
{ // 函數(shù)名cout << useF(f, 11.11) << endl;// 函數(shù)對(duì)象cout << useF(Functor(), 11.11) << endl;// lamber表達(dá)式cout << useF([](double d){ return d / 4; }, 11.11) << endl;return 0;
}
2)、包裝器原型
std::function在頭文件<functional>
// 類模板原型如下
template <class T> function; // undefined
template <class Ret, class... Args>
class function<Ret(Args...)>;
模板參數(shù)說明:
Ret: 被調(diào)用函數(shù)的返回類型
Args…:被調(diào)用函數(shù)的形參
即現(xiàn)在存在一個(gè)包裝器為:function<int(int, int)>
,該包裝器將所有的參數(shù)為2個(gè)int,返回值為int的所有可調(diào)用對(duì)象進(jìn)行統(tǒng)一,認(rèn)為是一個(gè)類型!!
3)、使用
template<class F, class T>
T useF(F f, T x)
{static int count = 0;cout << "count:" << ++count << endl;cout << "count:" << &count << endl;return f(x);
}
double f(double i)
{return i / 2;
}
struct Functor
{double operator()(double d){return d / 3;}
};int main()
{// 函數(shù)名std::function<double(double)> func1 = f;cout << useF(func1, 11.11) << endl;// 函數(shù)對(duì)象std::function<double(double)> func2 = Functor();cout << useF(func2, 11.11) << endl;// lamber表達(dá)式std::function<double(double)> func3 = [](double d){return d;};cout << useF(func3, 11.11) << endl;return 0;
}
4)、面試題
150. 逆波蘭表達(dá)式求值
class Solution {
public:int evalRPN(vector<string>& tokens) {unordered_map<string, function<int(int, int)>> ophash = {{"+", [](int x, int y){return x + y;}},{"-", [](int x, int y){return x - y;}},{"*", [](int x, int y){return x * y;}},{"/", [](int x, int y){return x / y;}}};stack<int> st;for(auto str : tokens){if(ophash .find(str) != ophash .end()){int right = st.top(); st.pop();int left = st.top(); st.pop();st.push(ophash [str](left, right));}elsest.push(stoi(str));}return st.top();}
};
三、bind綁定
?bind也是一個(gè)函數(shù)模板,可以接收一個(gè)可調(diào)用對(duì)象,并返回一個(gè)新的可調(diào)用對(duì)象,用于調(diào)整參數(shù)的個(gè)數(shù)和順序!!
// 原型如下:
template <class Fn, class... Args>
/* unspecified */ bind (Fn&& fn, Args&&... args);
// with return type (2)
template <class Ret, class Fn, class... Args>
/* unspecified */ bind (Fn&& fn, Args&&... args);
?調(diào)用bind的一般形式:auto newCallable = bind(callable,arg_list);其中,newCallable本身是一個(gè)可調(diào)用對(duì)象,arg_list是一個(gè)逗號(hào)分隔的參數(shù)列表,對(duì)應(yīng)給定的callable的參數(shù)。當(dāng)我們調(diào)用newCallable時(shí),newCallable會(huì)調(diào)用callable,并傳給它arg_list中的參數(shù)。
?arg_list中的參數(shù)可能包含形如_n的名字,其中n是一個(gè)整數(shù),這些參數(shù)是“占位符”,表示newCallable的參數(shù),它們占據(jù)了傳遞給newCallable的參數(shù)的“位置”。數(shù)值n表示生成的可調(diào)用對(duì)象中參數(shù)的位置:_1為newCallable的第一個(gè)參數(shù),_2為第二個(gè)參數(shù),以此類推。
1)普通綁定用法
【實(shí)例】:
int Sub(int a, int b)
{return a - b;
}int main()
{std::function<int(int, int)> func1 = std::bind(Plus, std::placeholders::_1, std::placeholders::_2);std::cout << func1(10, 2) << std::endl;
}
?bind函數(shù)中,_1和_2都是占位符。當(dāng)執(zhí)行func1(10, 2)函數(shù)時(shí),參數(shù)10和2會(huì)被作為參數(shù)傳遞給Plus函數(shù)。其中std::placeholders::_1表示func1第一個(gè)參數(shù)的位置, std::placeholders::_2表示第二個(gè)參數(shù)所在位置!
2)、改變參數(shù)位置
?既然_1和_2是占位符,所以僅需改變兩者位置,所以func函數(shù)傳遞給Plus的參數(shù)即可轉(zhuǎn)換。具體結(jié)果如下:
int Sub(int a, int b)
{return a - b;
}int main()
{std::function<int(int, int)> func1 = std::bind(Sub, std::placeholders::_2, std::placeholders::_1);std::cout << func1(10, 2) << std::endl;
}
3)改變參數(shù)的個(gè)數(shù)
?我們?cè)陬愅庹{(diào)用一個(gè)類成員函數(shù),調(diào)用成員函數(shù)時(shí)第一個(gè)參數(shù)為該對(duì)象的指針。但每次我們手動(dòng)傳遞的時(shí)候非常麻煩。所以我們可以通過bind()將第一個(gè)參數(shù)進(jìn)行綁死,改變參數(shù)個(gè)數(shù)。具體如下:
class Plus
{
public:static int Plusi(int x, int y){return x + y;}double Plusd(double x, double y){return x + y;}
};
int main()
{Plus ps;// 正常情況下,第一個(gè)參數(shù)this指針需要手動(dòng)傳遞, 麻煩std::function<double(Plus*, double, double)> func1 = &Plus::Plusd;std::cout << func1(&ps, 10.1, 20.2) << std::endl;// 將第一個(gè)參數(shù)綁死為Plus*, std::function<double(double, double)> func2 = std::bind(&Plus::Plusd,&ps, std::placeholders::_1, std::placeholders::_2);std::cout << func2(10.1, 20.2) << std::endl;// 將第一個(gè)參數(shù)和第三個(gè)參數(shù)綁死std::function<double(double)> func3 = std::bind(&Plus::Plusd, &ps, std::placeholders::_1, 1.1);std::cout << func3(10.1) << std::endl;// 所有參數(shù)直接全部綁死, 注意此處博主綁定的是靜態(tài)函數(shù)auto func4 = std::bind(&Plus::Plusi, 10, 10);std::cout << func4() << std::endl;//綁定時(shí),第一個(gè)參數(shù)因?yàn)橹羔?#xff0c;但編譯器做了特殊處理,可以綁定臨時(shí)對(duì)象std::function<double(double, double)> func5 = std::bind(&Plus::Plusd, Plus(), std::placeholders::_1, std::placeholders::_2);std::cout << func5(1.1, 2.2) << std::endl;
}