Qt5中使用lambda表達(dá)式
c11新特性中加入了lambda表達(dá)式,所以Qt 也支持
需在.pro文件中加入
CONFIG?+=?c++11 例子:
?1????QString?program?=?"C:/Windows/System32/cmd.exe"; ?2?????QStringList?arguments; ?3?????arguments?<<?"/c"?<<?"dir"?<<?"C:\"; ?4?????QProcess*?cmdProcess?=?new?QProcess; ?5?????QObject::connect(cmdProcess,?&QProcess::readyRead,[=](){ ?6?????????QTextCodec?*codec?=?QTextCodec::codecForName("GBK"); ?7?????????QString?dir?=?codec->toUnicode(cmdProcess->readAll()); ?8?????????qDebug()?<<?dir; ?9?????}); 10?????cmdProcess->start(program,?arguments);
?
一段簡(jiǎn)單的Code
我也不是文藝的人,對(duì)于Lambda的歷史,以及Lambda與C++的那段淵源,我也不是很熟悉,技術(shù)人,講究拿代碼說事。
復(fù)制代碼 代碼如下:
#include
?
當(dāng)我第一次看到這段代碼時(shí),我直接凌亂了,直接看不懂啊。上面這段代碼,如果你看懂了,下面的內(nèi)容就當(dāng)時(shí)復(fù)習(xí)了;如果看不懂了,就接著和我一起總結(jié)吧。
基本語法
簡(jiǎn)單來說,Lambda函數(shù)也就是一個(gè)函數(shù),它的語法定義如下:
復(fù)制代碼 代碼如下:
[capture](parameters) mutable ->return-type{statement}
?
1.[capture]:捕捉列表。捕捉列表總是出現(xiàn)在Lambda函數(shù)的開始處。實(shí)際上,[]是Lambda引出符。編譯器根據(jù)該引出符判斷接下來的代碼是否是Lambda函數(shù)。捕捉列表能夠捕捉上下文中的變量以供Lambda函數(shù)使用;
2.(parameters):參數(shù)列表。與普通函數(shù)的參數(shù)列表一致。如果不需要參數(shù)傳遞,則可以連同括號(hào)“()”一起省略;
3.mutable:mutable修飾符。默認(rèn)情況下,Lambda函數(shù)總是一個(gè)const函數(shù),mutable可以取消其常量性。在使用該修飾符時(shí),參數(shù)列表不可省略(即使參數(shù)為空);
4.->return-type:返回類型。用追蹤返回類型形式聲明函數(shù)的返回類型。我們可以在不需要返回值的時(shí)候也可以連同符號(hào)”->”一起省略。此外,在返回類型明確的情況下,也可以省略該部分,讓編譯器對(duì)返回類型進(jìn)行推導(dǎo);
5.{statement}:函數(shù)體。內(nèi)容與普通函數(shù)一樣,不過除了可以使用參數(shù)之外,還可以使用所有捕獲的變量。
與普通函數(shù)最大的區(qū)別是,除了可以使用參數(shù)以外,Lambda函數(shù)還可以通過捕獲列表訪問一些上下文中的數(shù)據(jù)。具體地,捕捉列表描述了上下文中哪些數(shù)據(jù)可以被Lambda使用,以及使用方式(以值傳遞的方式或引用傳遞的方式)。語法上,在“[]”包括起來的是捕捉列表,捕捉列表由多個(gè)捕捉項(xiàng)組成,并以逗號(hào)分隔。捕捉列表有以下幾種形式:
1.[var]表示值傳遞方式捕捉變量var;
2.[=]表示值傳遞方式捕捉所有父作用域的變量(包括this);
3.[&var]表示引用傳遞捕捉變量var;
4.[&]表示引用傳遞方式捕捉所有父作用域的變量(包括this);
5.[this]表示值傳遞方式捕捉當(dāng)前的this指針。
上面提到了一個(gè)父作用域,也就是包含Lambda函數(shù)的語句塊,說通俗點(diǎn)就是包含Lambda的“{}”代碼塊。上面的捕捉列表還可以進(jìn)行組合,例如:
1.[=,&a,&b]表示以引用傳遞的方式捕捉變量a和b,以值傳遞方式捕捉其它所有變量;
2.[&,a,this]表示以值傳遞的方式捕捉變量a和this,引用傳遞方式捕捉其它所有變量。
不過值得注意的是,捕捉列表不允許變量重復(fù)傳遞。下面一些例子就是典型的重復(fù),會(huì)導(dǎo)致編譯時(shí)期的錯(cuò)誤。例如:
3.[=,a]這里已經(jīng)以值傳遞方式捕捉了所有變量,但是重復(fù)捕捉a了,會(huì)報(bào)錯(cuò)的;
4.[&,&this]這里&已經(jīng)以引用傳遞方式捕捉了所有變量,再捕捉this也是一種重復(fù)。
Lambda的使用
對(duì)于Lambda的使用,說實(shí)話,我沒有什么多說的,個(gè)人理解,在沒有Lambda之前的C++ , 我們也是那樣好好的使用,并沒有對(duì)缺少Lambda的C++有什么抱怨,而現(xiàn)在有了Lambda表達(dá)式,只是更多的方便了我們?nèi)懘a。不知道大家是否記得C++ STL庫(kù)中的仿函數(shù)對(duì)象,仿函數(shù)想對(duì)于普通函數(shù)來說,仿函數(shù)可以擁有初始化狀態(tài),而這些初始化狀態(tài)是在聲明仿函數(shù)對(duì)象時(shí),通過參數(shù)指定的,一般都是保存在仿函數(shù)對(duì)象的私有變量中;在C++中,對(duì)于要求具有狀態(tài)的函數(shù),我們一般都是使用仿函數(shù)來實(shí)現(xiàn),比如以下代碼:
復(fù)制代碼 代碼如下:
#include
?
現(xiàn)在我們有了Lambda這個(gè)利器,那是不是可以重寫上面的實(shí)現(xiàn)呢?看代碼:
復(fù)制代碼 代碼如下:
#include
?
顯而易見的效果,代碼簡(jiǎn)單了,你也少寫了一些代碼,也去試一試C++中的Lambda表達(dá)式吧。
關(guān)于Lambda那些奇葩的東西
看以下一段代碼:
復(fù)制代碼 代碼如下:
#include
?
程序輸出結(jié)果如下:
復(fù)制代碼 代碼如下:
by_val_lambda: 11
by_ref_lambda: 11
by_val_lambda: 11
by_ref_lambda: 12
你想到了么???那這又是為什么呢?為什么第三個(gè)輸出不是12呢?
在by_val_lambda中,j被視為一個(gè)常量,一旦初始化后不會(huì)再改變(可以認(rèn)為之后只是一個(gè)跟父作用域中j同名的常量),而在by_ref_lambda中,j仍然在使用父作用域中的值。所以,在使用Lambda函數(shù)的時(shí)候,如果需要捕捉的值成為L(zhǎng)ambda函數(shù)的常量,我們通常會(huì)使用按值傳遞的方式捕捉;相反的,如果需要捕捉的值成成為L(zhǎng)ambda函數(shù)運(yùn)行時(shí)的變量,則應(yīng)該采用按引用方式進(jìn)行捕捉。
再來一段更暈的代碼:
復(fù)制代碼 代碼如下:
#include
?
這段代碼主要是用來理解Lambda表達(dá)式中的mutable關(guān)鍵字的。默認(rèn)情況下,Lambda函數(shù)總是一個(gè)const函數(shù),mutable可以取消其常量性。按照規(guī)定,一個(gè)const的成員函數(shù)是不能在函數(shù)體內(nèi)修改非靜態(tài)成員變量的值。例如上面的Lambda表達(dá)式可以看成以下仿函數(shù)代碼:
復(fù)制代碼 代碼如下:
class const_val_lambda{public:const_val_lambda(int v) : val(v) {}void operator()() const { val = 3; } // 常量成員函數(shù)private:int val;};
?
對(duì)于const的成員函數(shù),修改非靜態(tài)的成員變量,所以就出錯(cuò)了。而對(duì)于引用的傳遞方式,并不會(huì)改變引用本身,而只會(huì)改變引用的值,因此就不會(huì)報(bào)錯(cuò)了。都是一些糾結(jié)的規(guī)則。慢慢理解吧。