C++拾遺--lambda表達式
前言
有時,我們需要在函數內部頻繁地使用某一功能。此時,我們可以把這種功能寫成一個獨立的函數。而實際上,這個新的函數很可能是不需要在其它的地方進行調用的。我們想限定它的作用範圍,最好是僅限於當前函數。而函數的內部是不可以重新定義其它的函數的。爲了解決這個問題,在新的標準中,C++引入了lambda表達式(lambda expression)的概念。有了lambda表達式,C++向一門完美的語言又進了一大步。總的來說,lambda表達式極大地提升了C++的函數運用能力。
lambda表達式
《C++Primer》中對它的描述是“一個lambda表達式表示一個可調用的代碼單元,可理解爲一個未命名的內聯函數”。lambda表達式的一般形式是
[capture list] (parameter list) ->return type {function body}
- capture list -> 捕獲列表(必選)
- parameter list -> 參數列表(可選)
- function body -> 函數主體(必選)
- return type -> 返回值類型(可選)
下面我們一一探討
感性認識
#include <iostream>
#include <string>
using namespace std;
int main()
{
//定義一個lambda表達式
auto print = [](string s){
for (int i = 0; i < s.size(); i++)
cout << s[i] << " ";
cout << endl;
};
string man = "man";
string woman = "woman";
string say = "ILOVEYOUBABY";
//對print的調用形同一個函數
print(man);
print(woman);
print(say);
cin.get();
return 0;
}
運行
capture list(捕獲列表)
在捕獲列表中指明需要用到的局部變量(全局變量可直接使用,不需捕獲)。兩種捕獲方式:值捕獲、引用捕獲。
需要指出:捕獲列表只用於捕獲局部非static變量。
1.值捕獲
- 前提:被捕獲的變量是可以被拷貝的。
- 重點:在值捕獲時,默認情況下,是不可以修改捕獲列表中變量的值的,除非在parameter list後加關鍵字mutable。
- 難點:拷貝的時機是在lambda表達式定義時,而不是使用時。
#include <iostream>
using namespace std;
int g_data(1);
int main()
{
//data的定義必須在lambda表達式之前,否則無法捕獲
int data(2);
auto fun = [data]()mutable{
//在lambda表達式中,修正data的值
data = 3; //若不加mutable,此處會error
g_data = 4;
};
cout << "fun()調用之前" << endl;
cout << "g_data = " << g_data << ends << "data = " << data << endl;
//修正data的值
data = 5;
//在修正後進行調用,以驗證值捕獲的時機
fun();
cout << "fun()調用之後" << endl;
cout << "g_data = " << g_data << ends << "data = " << data << endl;
cin.get();
return 0;
}
運行2.引用捕獲
#include <iostream>
using namespace std;
int main()
{
cout << "引用捕獲演示" << endl;
int data(0);
cout << "fun()調用之前 ";
cout << "data = " << data << endl;
auto fun = [&data](){
data++; //由於是引用捕獲,在修改值時,mutable可以不加
};
//調用fun()
fun();
cout << "fun()調用之後 ";
cout << "data = " << data << endl;
cin.get();
return 0;
}
運行隱式捕獲
- [&] 所有變量均採用引用捕獲。
- [=] 所有變量均採用值捕獲。
- [&,identifier_list] identifier_list是一個用逗號隔開的參數列表,這個列表中的局部變量使用值捕獲,其它的使用引用捕獲。
- [=,identifier_list] identifier_list是一個用逗號隔開的參數列表,這個列表中的局部變量使用引用捕獲,且變量名前需添加&,其它的使用值捕獲。
#include <iostream>
using namespace std;
int main()
{
int a, b, c;
a = b = c = 0;
//在fun1中a、b、c都採用值捕獲
auto fun1 = [=]()mutable{
a++;
b++;
c++;
};
//在fun2中a、b、c都採用引用捕獲
auto fun2 = [&](){
a++;
b++;
c++;
};
//在fun3中a採用引用捕獲,b、c採用值捕獲
auto fun3 = [=, &a](){
a++;
};
//在fun4中b、c採用引用捕獲,a採用值捕獲
auto fun4 = [&, a](){
b++;
c++;
};
fun1();
cout << "fun1() a = " << a << " b = " << b << " c = " << c << endl;
a = b = c = 0;
fun2();
cout << "fun2() a = " << a << " b = " << b << " c = " << c << endl;
a = b = c = 0;
fun3();
cout << "fun3() a = " << a << " b = " << b << " c = " << c << endl;
a = b = c = 0;
fun4();
cout << "fun4() a = " << a << " b = " << b << " c = " << c << endl;
cin.get();
return 0;
}
運行parameter list(參數列表)
function body和return type
- 若function body中只有一條return語句,則return type可以沒有,返回值類型由return語句推測。
- 若無return語句,則返回值類型爲void.
- 若除了return語句外還有其它語句,則必須指定返回值的類型,且必須使用尾置返回類型,即"->類型名"的形式。