前言
有時,我們需要在函數內部頻繁地使用某一功能。此時,我們可以把這種功能寫成一個獨立的函數。而實際上,這個新的函數很可能是不需要在其它的地方進行調用的。我們想限定它的作用范圍,最好是僅限於當前函數。而函數的內部是不可以重新定義其它的函數的。為了解決這個問題,在新的標准中,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是一個用逗號隔開的參數列表,這個列表中的局部變量使用引用捕獲,且變量名前需添加&,其它的使用值捕獲。
特別的,空捕獲列表[]:表示lambda表達式中不能使用任何局部變量。
實例
#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(參數列表)
參數列表和普通函數的參數列表用法基本一致,除了一點:不可以有默認實參。
即是不可以有這種寫法:[](int a=0){};
function body和return type
三點規則:
若function body中只有一條return語句,則return type可以沒有,返回值類型由return語句推測。
若無return語句,則返回值類型為void.
若除了return語句外還有其它語句,則必須指定返回值的類型,且必須使用尾置返回類型,即"->類型名"的形式。
------------------------------分割線------------------------------
C++ Primer Plus 第6版 中文版 清晰有書簽PDF+源代碼 http://www.linuxidc.com/Linux/2014-05/101227.htm
讀C++ Primer 之構造函數陷阱 http://www.linuxidc.com/Linux/2011-08/40176.htm
讀C++ Primer 之智能指針 http://www.linuxidc.com/Linux/2011-08/40177.htm
讀C++ Primer 之句柄類 http://www.linuxidc.com/Linux/2011-08/40175.htm
將C語言梳理一下,分布在以下10個章節中: