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