欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于C++ Lambda表達(dá)式的程序優(yōu)化

 更新時(shí)間:2017年02月15日 09:55:25   投稿:mrr  
這篇文章主要介紹了基于C++ Lambda表達(dá)式的程序優(yōu)化的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下

什么是Lambda?

C++ 11加入了一個(gè)非常重要的特性——Lambda表達(dá)式。營里(戴維營)的兄弟都對Objective-C很熟悉,許多人多block情有獨(dú)鐘,將各種回調(diào)函數(shù)、代理通通都用它來實(shí)現(xiàn)。甚至有人選擇用FBKVOController、BlocksKit等開源框架將KVO、控件事件處理都改為通過block解決。原因就是簡單、方便、直觀,函數(shù)的定義和使用出現(xiàn)在同一個(gè)地方。這里的Lambda表達(dá)式實(shí)際上和block非常類似,當(dāng)然如果你用它和Swift語言的閉包比較,那就是一回事了。

這是一個(gè)關(guān)于C\C++程序員的一個(gè)小故事,關(guān)于C++11——剛剛通過的新標(biāo)準(zhǔn)的一個(gè)小故事…

請不要誤會,題目中所提及的“優(yōu)化”并不是提升程序的性能——Lambda表達(dá)式干不了這個(gè)。從本質(zhì)上來說,它只是一種“語法糖”而已。不使用這種表達(dá)式,我們照樣可以寫出滿足需求的程序。正如放棄C而使用匯編,或者放棄匯編而使用機(jī)器語言一樣,你能控制的范圍就在那里,不增不減。但如果有得選擇,我相信大部分人會選擇匯編而非機(jī)器語言,選擇C而非匯編,甚至選擇C++而非C語言……。如果你確實(shí)是這樣選擇的,那么我有理由相信,你會選擇C++新標(biāo)準(zhǔn)中的Lambda表達(dá)式,因?yàn)樗_實(shí)能夠簡化你的程序,讓你寫起程序來更容易;讓你的程序更易讀,更優(yōu)美;同時(shí)也讓你有更多向同行炫耀的資本。

從一個(gè)實(shí)際的應(yīng)用說起

讓我們還是看一個(gè)例子吧。

無論是C語言的使用者,還是C++的用戶,如果你從事PC程序的算法開發(fā),我有96.57%的把握認(rèn)為你可能使用過C++標(biāo)準(zhǔn)模板庫STL(其中的string,vector之類)。畢竟,STL的抽象不錯(cuò),不用白不用,是不是。STL中有一大類是算法,這些算法的抽象同樣不錯(cuò),我們就拿排序算法(sort)來說事吧。

假設(shè)現(xiàn)在有一個(gè)結(jié)構(gòu)稱為Student,其中包含了ID與name兩項(xiàng)——分別表示學(xué)號與姓名。在某個(gè)應(yīng)用中,用戶希望對一個(gè)Student的數(shù)組按照ID的從大到小排序,那么程序可能寫成如下的形式(本文中的所有程序均在Visual Studio 2010下編譯通過):

#include <string>
#include <vector>
#include <iostream>
#include <iterator>
#include <algorithm>
using namespace std;
struct Student {
unsigned ID;
string name;
Student(unsigned i, string n) : ID(i), name(n){}
};
struct compareID {
bool operator ()(const Student& val1, const Student& val2)  const {
return val1.ID < val2.ID;
}
};
int main(int argc, char* argv[]) {
Student a[] = {Student(2, “John”), Student(0, “Tom”), Student(1, “Lily”)};
sort(a, a+3, compareID());
for(int i=0; i<3; ++i)
cout<<a[i].ID<<' ‘<<a[i].name<<endl;
return 0
}

程序用sort進(jìn)行排序,之后用一個(gè)for循環(huán)輸出結(jié)果。而之所以能完成這個(gè)排序,則是由于仿函數(shù)compardID的存在。

現(xiàn)在假設(shè)用戶的需求變了(或者是另一個(gè)需求),需要你按照學(xué)生的姓名進(jìn)行排序,那么你需要重新寫一個(gè)仿函數(shù)如下:

struct compareName {
bool operator ()(const Student& val1, const Student& val2) const {
return val1.name < val2.name;
}
};

然后將sort的調(diào)用修改為:

sort(a, a+3, compareName());

問題出現(xiàn)了,你意識到了嗎?你只是想表達(dá)一個(gè)很簡單的排序方式,確不得不引入很多的代碼行來建相應(yīng)的仿函數(shù)。如果這個(gè)函數(shù)在很多地方都會用到,那么建立它的價(jià)值還相對較大。如果只是用在一個(gè)地方,你也不得不中段你流暢是思路,一邊罵娘一邊寫出這么多行代碼。另一方面,程序的讀者在讀到相應(yīng)部分的時(shí)候,也不得不中段他流暢的思路,在工程的某個(gè)地方苦苦求索——compareName或者compareID是怎么干的呢?

是的,是的,作為一個(gè)C++老鳥,你會說,這樣寫代碼太不專業(yè)了。完全可以有不建立仿函數(shù)的寫法,比如以ID排序時(shí),完全可以通過引入boost庫中的bind來實(shí)現(xiàn),比如這樣:

sort(a, a+3, bind(less<unsigned>(), bind(&Student::ID, _1), bind(&Student::ID, _2)));

如果你能寫出或是讀懂這段代碼,我承認(rèn)你的C++水平確實(shí)說得過去(如果讀不懂,沒關(guān)系,它不是本文的重點(diǎn))。但這段代碼真的好嗎?確實(shí),這樣可以省略了仿函數(shù)。但問題是代碼的復(fù)雜性大大增加了——即使如此簡單的一個(gè)需求,bind表達(dá)式也要復(fù)雜如斯,更復(fù)雜一點(diǎn)的需求要寫成何等復(fù)雜的形式啊,這對于bind本身,寫程序的人,讀程序的人都是一種折磨——你hold住嗎?

如果用Lambda表達(dá)式呢,唔,這個(gè)sort語句可以這么寫:

sort(a, a+3, [](const Student& val1, const Student& val2){ return val1.ID < val2.ID; });

那個(gè)看上去有點(diǎn)奇怪的,sort的第三個(gè)函數(shù)就是一個(gè)Lambda表達(dá)式了。如果我們除去開頭的“[]”不看,后面的部分很像一個(gè)函數(shù)——你可以很容易地看出這個(gè)函數(shù)是干什么的:給定兩個(gè)Student元素,比較兩個(gè)元素的ID值,并返回比較結(jié)果——這玩意兒比上面那個(gè)bind結(jié)果容易閱讀多了。
事實(shí)上,利用Lambda表達(dá)式,上述程序可以修改為如下的樣子(只列出了main函數(shù)):

int main(int argc, char* argv[]) {
Student a[] = {Student(2, “John”), Student(0, “Tom”), Student(1, “Lily”)};
sort(a, a+3, [](const Student& val1, const Student& val2){ return val1.ID < val2.ID; });
for_each(a, a+3, [](const Student& val){cout<<val.ID<<' ‘<<val.name<<endl;});
return 0
}

其中的for_each句用于輸出——其中的Lambda表達(dá)式意味著:對于每一個(gè)val,輸出其ID與Name值——這樣我們連for循環(huán)也省了。

Lambda表達(dá)式的引入就是為了更方便地書寫程序,更容易地閱讀程序。如同STL一樣,有什么理由不去用呢?

Lambda表達(dá)式的基本語法

有了感性的認(rèn)識后,我們來分析一下Lambda表達(dá)式的語法。

我這里無意把C++標(biāo)準(zhǔn)草案中Lambda表達(dá)式的有關(guān)章節(jié)翻譯過來(我也不佩這么做)。只是在這里希望以最通俗的方式將它的語法講解一二。從結(jié)構(gòu)上說,Lambda表達(dá)式可以寫成如下的形式:

Lambda-introducer lambda-declarator(opt) compound-statement

其中的Lambda-introducer就是剛剛的那個(gè)“[]”它是不能省略的。中括號中也可能出現(xiàn)變量。表示將局部變量傳入到Lambda表達(dá)式中。lambda-declaratoropt是可選擇的,包括了表達(dá)式的參數(shù)列表,返回值信息, mutable聲明(以及一些其它信息,這里不做討論)。而最后的compound-statement則是表達(dá)式的主要內(nèi)容。

還是看一個(gè)例子吧:

int n = 10;
[n](int k) mutable -> int { return k + n; };

程序的第二行是一個(gè)lambda表達(dá)式,lambda里能出現(xiàn)的東西幾乎全了(當(dāng)然,正如我在前文說的,有一些其它信息這里不做討論,所以沒有加入其中)。讓我們對里面的東西一一分析:

  • l[n]是Lambda-introducer,而n是一個(gè)變量,表明該表達(dá)式作用域中的變量n將被傳入這個(gè)表達(dá)式。以本程序?yàn)槔?,傳入的值?0。Lambda-introducer可以指定變量以值的方式傳入,也可以用其它的形式指定其以引用的方式傳入。其變型大家就baidu一下吧J
  • l(int k)表示了參數(shù)列表,屬于lambda-declarator的一部分。你可以把表達(dá)式看成一個(gè)仿函數(shù)(如上文的)。這里指定了仿函數(shù)的參數(shù)列表。如果函數(shù)的參數(shù)列表為空,這一部分可以省略。
  • lmutable表示仿函數(shù)中的變量能否改變。以前文中compareID這個(gè)仿函數(shù)為例,注意到其中的operator ()是const的。如果lambda表達(dá)式中引入了這個(gè)mutable,則對應(yīng)的仿函數(shù)中operator()的定義將不包含這個(gè)const——這意味著仿函數(shù)中的變量值(Lambda-introducer傳入)可以改變。討論operator() const與operator()的區(qū)別已經(jīng)超出了本文的范圍,想了解的話,看看C++相關(guān)教程吧
  • l-> int 表示返回類型(這里是int)。如果編譯器能從代碼中推斷出返回類型,或者Lambda表達(dá)式的返回類型為void,則該項(xiàng)可省略;
  • l{ return k+n; }是compound-statement:函數(shù)體。

通過分析可以看出,這個(gè)Lambda表達(dá)式相當(dāng)于一個(gè)函數(shù),該函數(shù)讀入一個(gè)int值k,將該值加上n返回。根據(jù)上述說明,這個(gè)表達(dá)式可以簡寫為:

[n](int k){ return k + n; };

Lambda表達(dá)式可以存儲在std::function<T> 或 std:: reference_closure<T>類型的變量中。其中的T表示了表達(dá)式對應(yīng)函數(shù)的類型。以上述表達(dá)式為例,它輸入?yún)?shù)為int型變量,輸出為int,那么為了保存它,可以寫成如下的形式:

function<int(int)> g = [n](int k){ return k + n; };

另一個(gè)例子,前文所使用的Lambda表達(dá)式:

[](const Student& val1, const Student& val2){ return val1.ID < val2.ID; }

可以存儲于function<bool(const Student&, const Student&)>這個(gè)類型的變量中。

如果你嫌這么寫麻煩,也可以利用C++新標(biāo)準(zhǔn)中另一個(gè)新特性:類型推導(dǎo)。即用auto作為變量的類型,讓編譯器自己推導(dǎo)表達(dá)式的類型:

auto g = [n](int k){ return k + n; };

沒問題,這樣寫g還是一個(gè)強(qiáng)類型的變量,只不過其類型是由編譯器推導(dǎo)的,好處是你不用寫太長的變量類型了J

Lambda表達(dá)式進(jìn)階

作為結(jié)尾,我們來看一些C++ Lambda表達(dá)式進(jìn)階的用法。

Lambda表達(dá)式被引入主要是用于函數(shù)式編程。有了Lambda表達(dá)式,我們也可以做一些函數(shù)式編程的東西。比如將一個(gè)函數(shù)作為返回值的應(yīng)用:

auto g = [](int n) -> function<void (int)> {
return [n](int k){ cout<<n+k<<' ‘; };
};

它是一個(gè)Lambda表達(dá)式,輸入一個(gè)整型變量n,返回一個(gè)函數(shù)(lambda表達(dá)式),這個(gè)函數(shù)接收一個(gè)int值k,并打印出k+n。g的使用方法如下:

int a[]={1,2,3,4,5,6,7,8,9,0};
function<void (int)> f = g(2);
for_each(a, a+10, f);

它將輸出:3 4 5 6 7 8 9 10 11 2

有一點(diǎn)函數(shù)式編程的味道了

至于其它的東西,比如如下的表達(dá)式:

[](){}();

是一個(gè)有效的調(diào)用。其中“[](){}”表示一個(gè)Lambda表達(dá)式,其輸入?yún)?shù)為空,返回void,什么都不干。而最后的()表示調(diào)用其求值——雖然什么都不干,但編譯能通過,很唬人喔

好了,就寫到這里吧。關(guān)于Lambda表達(dá)式想說的最后一件事是:它是新標(biāo)準(zhǔn)C++11中定義的。老的編譯器不支持(這也是我用VS2010的原因)。想要用它,以及其它新標(biāo)準(zhǔn)帶來的好處嗎?嘿,你的家伙(指編譯器)該升級了。

相關(guān)文章

  • C++/GoLang如何實(shí)現(xiàn)自底向上的歸并排序

    C++/GoLang如何實(shí)現(xiàn)自底向上的歸并排序

    這篇文章主要給大家介紹了關(guān)于C++/GoLang如何實(shí)現(xiàn)自底向上的歸并排序的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • C++高級數(shù)據(jù)結(jié)構(gòu)之二叉查找樹

    C++高級數(shù)據(jù)結(jié)構(gòu)之二叉查找樹

    這篇文章主要介紹了C++高級數(shù)據(jù)結(jié)構(gòu)之二叉查找樹,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-05-05
  • Qt利用QPainter實(shí)現(xiàn)基本繪圖的示例詳解

    Qt利用QPainter實(shí)現(xiàn)基本繪圖的示例詳解

    Qt?中提供了強(qiáng)大的?2D?繪圖系統(tǒng),可以使用相同的?API?在屏幕和繪圖設(shè)備上進(jìn)行繪制,它主要基于QPainter、QPaintDevice?和?QPaintEngine?這三個(gè)類。本文主要和大家介紹一下QPainter實(shí)現(xiàn)的基本繪圖,感興趣的可以了解一下
    2022-12-12
  • C語言實(shí)現(xiàn)三角函數(shù)表

    C語言實(shí)現(xiàn)三角函數(shù)表

    這篇文章主要為大家詳細(xì)介紹了C語言三角函數(shù)表,打印出相對應(yīng)的三角函數(shù)值,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-06-06
  • C語言?使用qsort函數(shù)來進(jìn)行快速排序

    C語言?使用qsort函數(shù)來進(jìn)行快速排序

    排序方法有很多種:選擇排序,冒泡排序,歸并排序,快速排序等。?看名字都知道快速排序是目前公認(rèn)的一種比較好的排序算法。因?yàn)樗俣群芸?,所以系統(tǒng)也在庫里實(shí)現(xiàn)這個(gè)算法,便于我們的使用。?這就是qsort函數(shù)
    2022-02-02
  • C++ Boost Uuid超詳細(xì)講解

    C++ Boost Uuid超詳細(xì)講解

    Boost是為C++語言標(biāo)準(zhǔn)庫提供擴(kuò)展的一些C++程序庫的總稱。Boost庫是一個(gè)可移植、提供源代碼的C++庫,作為標(biāo)準(zhǔn)庫的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開發(fā)引擎之一,是為C++語言標(biāo)準(zhǔn)庫提供擴(kuò)展的一些C++程序庫的總稱
    2022-12-12
  • C++ 約瑟夫環(huán)的實(shí)例代碼

    C++ 約瑟夫環(huán)的實(shí)例代碼

    這篇文章主要介紹了C++ 約瑟夫環(huán)的實(shí)例代碼的相關(guān)資料,希望通過本文能幫助到大家,實(shí)現(xiàn)這樣的功能,需要的朋友可以參考下
    2017-10-10
  • C++掃雷游戲的簡單制作

    C++掃雷游戲的簡單制作

    這篇文章主要為大家詳細(xì)介紹了C++掃雷游戲的簡單制作,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • Linux UDP服務(wù)端和客戶端程序的實(shí)現(xiàn)

    Linux UDP服務(wù)端和客戶端程序的實(shí)現(xiàn)

    這篇文章主要介紹了Linux UDP服務(wù)端和客戶端程序的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • 淺析C++函數(shù)模板和類模板

    淺析C++函數(shù)模板和類模板

    C++語言的模板技術(shù)包括函數(shù)模板和類模板,模板技術(shù)是一種代碼重用技術(shù),函數(shù)和類是C++語言中兩種主要的重用代碼形式,這篇文章主要介紹了C++函數(shù)模板和類模板,需要的朋友可以參考下
    2022-07-07

最新評論