C++11 lambda表達式小結

簡介

lambda表達式是一個匿名內聯函數,可以定義別的函數體中,其形式如下:

[capture list](parameter list)->return type{funtion body}

從中可以看到,lambda只能使用尾置返回類型
尾置返回類型放在參數列表後邊以->開頭,然後再原來放返回類型的地方放一個auto。

結構

lambda不可缺少的部分是捕獲列表capture list和函數體funtion body,其他都可以忽略不寫。

return type

return type會根據funtion body中的內容來推斷,如果只含有一個return 語句,類型就從其推斷,否則就是void。如果不是上述情況,就需要自己定義一個返回類型,防止推斷爲void和期望返回的類型不符合的問題。

parameter list

parameter list需要實參和形參互相匹配,且lambda不能有默認參數,所以兩者屬於也要相等。

capture list

capture list是lambda所在函數中定義的局部變量,lambda可以對其進行捕獲然後進行使用,捕獲過程也分爲值和引用,使用時看是否需要對捕獲的變量進行修改和所捕獲的變量是否支持這種操作。

值捕獲和引用捕獲

值捕獲需要變量能被拷貝,比如IO流是不能被拷貝,這就只能用引用。
有時可能需要返回一個lambda,當返回時,此lambda就不能用到引用,否則就會出現函數將返回一個局部變量的引用,這是不合法的。
引用捕獲需要對象存在。

變量修改

lambda在捕獲的時候就對變量進行了複製(值捕獲時),所以希望能借此修改外部變量,應該時用引用。但是如果只需要就地對捕獲的變量進行修改並且不想對外部修改的話,就可以在值捕獲時在參數列表之後指明mutable關鍵字。

隱式和顯式捕獲

顯示就是直接寫出局部變量,隱式就是不在capture list中寫出名字,只寫捕獲方式,其中 = (代表值捕獲), & (代表引用捕獲),讓編譯器自己推斷要使用那些變量。
比如:

[ = ](string s1){return s1.size()>=length;}  //假設length爲一個局部變量,則此時採用值捕獲。

兩者也可以混搭,這有一個要求:capture list中第一個元素必須爲隱式捕獲,並且顯示和隱式捕獲的方式必須不同。
比如:

[ = ,&os](string &s){ os << s << tmp; } //假設tmp爲局部變量,採用了值捕獲,則只能用顯示捕獲

捕獲列表小結:

列表 含義
[] 空捕獲列表
[n1,&n2,n3,&n4…] 以逗號爲分隔的捕獲列表,顯示捕獲
[&] 隱式捕獲,lambda中使用的變量全部採用引用捕獲
[=] 隱式捕獲,lambda中使用的變量全部採用值捕獲
[&,n1,n2] 混和捕獲,n1和n2值捕獲,其餘爲引用捕獲
[=,&n1,&n2] 混和捕獲,n1和n2引用捕獲,其餘爲值捕獲

examples

#include<bits/stdc++.h>
using namespace std;
void elimDups(vector<string>& words) {
	sort(words.begin(), words.end());
	auto end_unique = unique(words.begin(), words.end());
	//for (auto i : words)cout << i << " "; cout << endl;
	words.erase(end_unique, words.end());
	//for (auto i : words)cout << i << " "; cout << endl;
}

//countwords返回一個計數值,表示有多少個元素長度大於等於sz
int countwords(vector<string>& words, vector<string>::size_type sz) {
	elimDups(words);//字典序排序,刪除重複元素;
	stable_sort(words.begin(), words.end(), [](const string& s1, const string& s2) {return s1.size() < s2.size(); });//長度排序,長度相同也維持字典序
	//for (auto i : words)cout << i << " "; cout << endl;
    auto it = count_if(words.begin(), words.end(), [sz](const string& s) { return s.size() >= sz; });
	return it;
}
int main(void) {
	vector<string>words;
	string str;
	while (cin >> str) {
		words.push_back(str);
	}
	//for (auto i : words)cout << i << " "; cout << endl;
	int cnt = countwords(words, 5);//計算有多少個元素長度大於等於5
	cout << cnt << endl;
	//the quick red fox jumps over the slow red turtle
	auto f=[&]()->bool  {
		while (cnt > 0)cnt--;
		if (cnt == 0)return true;
	};
	cout << f() << endl;//調用lambda改變變量
	cout << cnt << endl;
	cout << f() << endl;//再調用lambda不再改變變量
	cout << cnt << endl;
	return 0;
}
input:
the quick red fox jumps over the slow red turtle
output:
3
1
0
1
0

problems

1.爲什麼需要使用mutable才能進行修改?

lambda在定義時,編譯器就會生成一個對應的匿名類,該類會包含所有被捕獲的變量作爲數據成員初始化,並且該類的operator()默認時const,這就導致無法修改類中的成員函數,加上mutable,即可轉換爲非const,就可以就地修改了。

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