日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

必须使用列别名命名此表达式_lambda表达式

發(fā)布時(shí)間:2023/12/13 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 必须使用列别名命名此表达式_lambda表达式 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一般的,如果一個(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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。