必须使用列别名命名此表达式_lambda表达式
一般的,如果一個(gè)類定義了函數(shù)調(diào)用運(yùn)算符,則我們可以像使用函數(shù)一樣使用這個(gè)類,例如:一個(gè)類A定義了函數(shù)調(diào)用運(yùn)算符,我們就可以使用A()這樣的形式調(diào)用對象,實(shí)際上調(diào)用了類的調(diào)用運(yùn)算符函數(shù)。如果一個(gè)類定義了調(diào)用運(yùn)算符,則該類的對象可以被稱為函數(shù)對象(可調(diào)用對象包含:函數(shù),函數(shù)指針,重載了函數(shù)調(diào)用運(yùn)算符的類和lambda表達(dá)式)。在lambda表達(dá)式中,編譯器將改表達(dá)式翻譯為一個(gè)未命名的類的未命名對象。lambda表達(dá)式產(chǎn)生的類中含有一個(gè)重載的函數(shù)調(diào)用運(yùn)算符。默認(rèn)情況下,lambda不能改變它捕獲的變量(可以通過mutable關(guān)鍵字進(jìn)行修改,后面會介紹)。因此,由lambda表達(dá)式產(chǎn)生的類中含有一個(gè)函數(shù)調(diào)用運(yùn)算符的const成員函數(shù)(const成員函數(shù)有常量對象調(diào)用,一般不改變類的成員變量,例如get一個(gè)成員變量,應(yīng)該在函數(shù)的參數(shù)列表后加上const關(guān)鍵字)。lambda表達(dá)式產(chǎn)生的類中不包含默認(rèn)構(gòu)造函數(shù),賦值運(yùn)算符和默認(rèn)析構(gòu)函數(shù)。是否含有默認(rèn)的拷貝/移動構(gòu)造函數(shù)則通常要視捕獲的對象的類型而定。
lambda表達(dá)式來自于lambda演算,其定義如下:
λ演算_百度百科?baike.baidu.com這里主要介紹下c++中的lambda表達(dá)式。
lambda表達(dá)式又被稱為匿名函數(shù),當(dāng)我們在程序的某一處使用一個(gè)簡單的函數(shù),并且只在此處或者此作用域中使用一次或者幾次,這時(shí)可以考慮使用lambda表達(dá)式。其基本語法如下:
lambda表達(dá)式的返回類型必須是尾置的。其中,參數(shù)列表和返回類型(返回類型忽略時(shí),lambda可以根據(jù)其函數(shù)體中返回類型進(jìn)行推斷)可以忽略。lambda表達(dá)式不能有默認(rèn)參數(shù),因此形參和實(shí)參的數(shù)量必須一致且一 一對應(yīng)。lambda表達(dá)式內(nèi)部是無法使用其所在函數(shù)中的(非static)變量的,但有時(shí)必須使用,就必須使用捕獲列表來捕獲其所在作用域中的參數(shù)(注意:只能捕獲lambda所在作用域中的參數(shù),函數(shù)外的變量可以直接使用。例如:我們在lambda表達(dá)式函數(shù)體中使用的cout,可以直接使用)。根據(jù)捕獲參數(shù)的方式,可以分為:值捕獲,引用捕獲,隱式捕獲和表達(dá)式捕獲。
捕獲列表的形式如下:
1 值捕獲
通過值捕獲的變量會被拷貝到lambda產(chǎn)生的類對象中,因此這種捕獲方式必須為每個(gè)值捕獲的變量建立對應(yīng)的數(shù)據(jù)成員。同時(shí)創(chuàng)建構(gòu)造函數(shù),令其捕獲的變量初始化數(shù)據(jù)成員。值捕獲的對象必須是可拷貝的。但其捕獲的值是在lambda表達(dá)式對象創(chuàng)建時(shí)拷貝,而不是運(yùn)行時(shí)拷貝:
//按值捕獲int t=10;auto ff=[t]() mutable { //注意:這里是lambda函數(shù)的聲明return ++t; //這里生成了一個(gè)_t的變量};auto ff2=[t]() mutable { //注意:這里是lambda函數(shù)的聲明return ++t; //這里生成了一個(gè)_t的變量};cout<<ff()<<endl; //這里調(diào)用lambda表達(dá)式cout<<ff2()<<endl;cout<<ff()<<endl;cout<<ff2()<<endl;cout<<t<<endl;/*運(yùn)行結(jié)果 11 11 12 12 10 */上述ff和ff2其本質(zhì)是編譯器生成的未命名類的未命名對象。由于是值捕獲,因此++t只在lambda函數(shù)作用域有效,捕獲t后實(shí)際在內(nèi)部生成了一個(gè)_t的成員變量。lambda表達(dá)式內(nèi)部對t的操作實(shí)際上是對_t這個(gè)變量的操作,并不影響其外部的t的值。
默認(rèn)我們捕獲到lambda表達(dá)式中的值是const的,是不能修改的,mutable關(guān)鍵字可允許我們對捕獲到的值進(jìn)行修改。因此,在上述代碼中,++t的時(shí)候必須加上mutable。上述lambda表達(dá)式等價(jià)于:
class cfun{ public:fun(t):_t(t){};bool operator(){ //由于這里使用了mutable關(guān)鍵字,因此是這樣的_t++;}/*當(dāng)沒有mutable關(guān)鍵字時(shí),函數(shù)調(diào)用運(yùn)算符重載如下形式:bool operator() const{/* 對_t的一些操作 */}*/private:int _t; };可變lambda
這里 再簡單介紹下mutable的使用。默認(rèn)情況下,lambda不會改變一個(gè)值被拷貝的變量。如果希望改變被捕獲的變量,就必須使用mutable。因此,可變lambda可以省略參數(shù)列表。
void fun(){size_t v1=42;auto f=[v1] () mutable { return ++v1; };v1=0;auto j=f(); //j=43 }一個(gè)引用捕獲的變量是否可以修改依賴于引用指向一個(gè)const對象還是非const對象。
void fun(){size_t v1=42; //局部變量//v1是一個(gè)非const的變量引用,可以使用f來改變其值。auto f=[&v1] { return ++v1; };v1=0;auto j=f(); //j=1 }2 引用捕獲
當(dāng)lambda用引用捕獲變量時(shí),由程序負(fù)責(zé)確保lambda執(zhí)行時(shí)引用所引的對象確實(shí)存在。因此,編譯器可以直接使用該引用而無需在lambda產(chǎn)生的類中將其存儲為數(shù)據(jù)成員。
//引用捕獲 int t=10; auto ff=[&t]() {cout<<t<<endl;t=13; }; t=11; ff(); cout<<t<<endl;//輸出結(jié)果 /* 11 13 */可以看到,引用捕獲的方式跟一般的引用形參函數(shù)類似,可以改變傳入的參數(shù)值。
引用捕獲是必要的,例如:
for_each(words.begin(),words.end(), [&os, c] (const string & s) { os<<s<<c; });因?yàn)閛stream對象os是不能拷貝的。
當(dāng)然,我們也可以從一個(gè)函數(shù)中返回一個(gè)lambda,但是lambda在返回后,函數(shù)中的變量會被銷毀,因此,lambda的捕獲列表中不能包含函數(shù)中變量的引用。
3 隱式捕獲
以上兩種方式都是顯式捕獲方式,這里介紹下隱式捕獲。編譯器可以根據(jù)lambda函數(shù)體中的代碼推斷我們會使用那些變量。其中&告訴編譯器引用捕獲方式,=采用值捕獲方式。
int a=1,b=2; [a,b](){cout<<a<<"+"<<b<<endl; }();//引用捕獲 [&](){cout<<a<<"+"<<b<<endl; }();//值捕獲 [=](){cout<<a<<"+"<<b<<endl; }();//混合使用 int c=3,d=4; [=,&c,&d](){cout<<a<<"+"<<b<<endl;cout<<c++<<"+"<<++d<<endl; }();當(dāng)我們使用混合方式時(shí),捕獲列表的第一個(gè)元素必須是&或者=。此符號指定了默認(rèn)捕獲方式。顯式捕獲必須使用與隱式捕獲不同的方式。即,當(dāng)默認(rèn)捕獲方式是值捕獲時(shí),顯式捕獲方式命名變量必須采用引用捕獲方式。
4 指定lambda返回類型
如果lambda函數(shù)體中包含了除return的任何語句,編譯器默認(rèn)此lambda返回void。例如:
void fun(){auto ff4=[](int i){if(i<0)return -i;elsereturn i;};cout<<ff4(-100)<<endl; }此時(shí)會出現(xiàn)編譯錯(cuò)誤,正確的寫法如下:
void fun(){auto ff4=[](int i)->int{if(i<0)return -i;elsereturn i;};cout<<ff4(-100)<<endl; }以下是一個(gè)lambda的使用例子:
void fun(){vector<int> vec={1,2,3,4,5};for(int i=0;i<vec.size();i++){if(vec[i]%2==0)cout<<vec[i]<<"是偶數(shù)"<<endl;elsecout<<vec[i]<<"是奇數(shù)"<<endl;}//高階寫法for_each(vec.begin(),vec.end(),[](int n){if(n%2==0)cout<<n<<"是偶數(shù)"<<endl;elsecout<<n<<"是奇數(shù)"<<endl;}); }總結(jié)
以上是生活随笔為你收集整理的必须使用列别名命名此表达式_lambda表达式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 02 字斟句酌
- 下一篇: 搜索引擎提交软件_增加SEO超级外链须知