淺出匿名函數lambda

跟python一樣。。。C++11終於也有了lambda函數了。。。大笑

個人感覺挺好用的,以下是個人的一些理解


基本的Lambda函數:

[捕獲的變量](參數)->返回值類型{函數體}

調用方法:

[捕獲的變量](參數)->返回值類型{函數體}(實參1,……,實參N);

各部分的解釋:

參數是指傳遞給lambda函數的參數,如可以(int a) 、(int a,int b) 、(int a,……,int z)當然也可以是無參數的();

返回值類型就是lambda函數返回的那個值的類型(= =,好像解釋了等於沒解釋); 

函數體是標識函數的實現;

返回值類型、參數、函數體都跟平常的函數差不多,只是返回值類型 換了個位置且前面多了個->,它們都可以被省略,如下面形式

[捕獲的變量](){}

注:當編譯器可以自動推斷出返回值類型纔可以將返回值類型省略。


[捕獲的變量]是lambda函數的開始,方括號[]不可以省略,但“捕獲的變量"是可以省略的,其是用來傳遞給編譯器自動生成的函數對象類的構造函數的。

它可以捕獲從作用域開始到lambda函數所在行的所有局部變量,使lambda函數能使用函數體外被捕獲的那些局部變量。爲什麼是局部變量呢?因爲它不能捕獲全局變量(偷笑這句話有點SB,請無視。)如下面的例子就是錯誤的:

int a=10;
int main()
{
	//嘗試捕獲一個全局變量
	std::cout<< [a](){return a;}()<<std::endl;   //這裏的[a]後面會講解;
}

編譯器提示錯誤:



它可以是下面的幾種形式:

[]          //不捕獲任何局部變量,嘗試使用任何未捕獲的局部變量是非法的,如下面代碼:

int main()
{
	int a=10;
	int b=3;
	std::cout<< []()->int{return a>b;}()<<std::endl;
}

編譯器提示錯誤:



[=]       //以傳值方式捕獲作用域中的所有變量,但傳遞給lambda的值是常量,下面的例子揭示了這點

int main()
{
	int a=10;
	//嘗試修改一個以值傳遞進行捕獲的局部變量
	std::cout<< [a](){a++;return a;}()<<std::endl;   //這裏的[a]後面會講解;
}

編譯器提示錯誤:



[&]       //以傳址方式捕獲作用域中的所有變量,可以在lambda函數中修改傳進去的值,且修改的值會影響原值,如下面的例子

int main()
{
	int a=10;
	//嘗試修改一個以值傳遞進行捕獲的局部變量
	std::cout<< [&a](){a++;return a;}()<<std::endl;   //這裏的[&a]後面會講解;
}

運行結果:



[x]          //以傳值的方式,只捕獲x,無法在lambda函數中使用其他未捕獲的變量

[&x]        //以傳址的方式,只捕獲x,無法在lambda函數中使用其他未捕獲的變量,如下面的代碼是錯誤的。

int main()
{
	int a=10;
	int b=0;
	//嘗試使用一個未捕獲的局部變量
	std::cout<< [&a](){b=20;return b;}()<<std::endl;
}

編譯器提示錯誤:


[=,&x]    //除x以傳址方式進行捕獲,其他的局部變量以傳值方式進行捕獲。

[&,x]       //除x以傳值方式進行捕獲,其他的局部變量以傳址方式進行捕獲。


也許有人會問,既然能傳遞參數,那還要這些捕獲的變量做什麼呢?

如下面這兩個代碼的返回結果是一樣的

int main()
{
	int a=10;
	int b=15;
	std::cout<< [a](int b){return a+b;}(b)<<std::endl;   //傳進一個參數b並捕獲局部變量a
	std::cout<<[](int a,int b){return a+b;}(a,b)<<std::endl; //傳進參數a,b
}

的確,如果不考慮傳進參數的個數,那麼這兩個的確是等價的,可是,考慮下如果只能傳進一個參數,卻要比較2個值呢?

如計算某個數組中值大於x的元素個數?

下面是一個例子

int main()
{
	int a=4;
	int arr[10]={1,2,3,4,5,6,7,8,9,10};
	std::cout<<std::count_if(arr,arr+10,[a](int b)->bool{return b>a;})<<std::endl;
}

其中count_if每次只傳給謂語函數一個值,如果你寫的是前面那種需要傳2個值的函數就行不通了。

(注:這樣寫並不是最好的,只是爲了說明捕獲變量的用途才寫成那樣的。下面的寫法更簡便(雖然lambda也是函數對象類。但我沒辦法把它寫成一個局部變量都不用的形式尷尬)

#include<functional>
int main()
{
	int arr[10]={1,2,3,4,5,6,7,8,9,10};
	std::cout<<std::count_if(arr,arr+10,bind2nd(std::greater<int>(),4))<<std::endl;
}

)


使用lambda的好處

簡潔性:你可以不用特意去定義一個只使用一次的函數。

方便性:如上面那個count_if的例子,你可以直接看到並修改函數體中的內容,如果不使用lambda函數,那你需要去定義一個函數,假設你的工程中有很多的函數,那你可能會浪費一點時間去查找你定義的那個函數。



大笑大笑文章寫道這裏就完鳥,受個人知識所限,如果錯誤,請留言指出。。害羞害羞


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章