跟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函數,那你需要去定義一個函數,假設你的工程中有很多的函數,那你可能會浪費一點時間去查找你定義的那個函數。
文章寫道這裏就完鳥,受個人知識所限,如果錯誤,請留言指出。。