C++拾遺--lambda表達式

                           C++拾遺--lambda表達式

前言

    有時,我們需要在函數內部頻繁地使用某一功能。此時,我們可以把這種功能寫成一個獨立的函數。而實際上,這個新的函數很可能是不需要在其它的地方進行調用的。我們想限定它的作用範圍,最好是僅限於當前函數。而函數的內部是不可以重新定義其它的函數的。爲了解決這個問題,在新的標準中,C++引入了lambda表達式(lambda expression)的概念。有了lambda表達式,C++向一門完美的語言又進了一大步。總的來說,lambda表達式極大地提升了C++的函數運用能力。

lambda表達式

    《C++Primer》中對它的描述是“一個lambda表達式表示一個可調用的代碼單元,可理解爲一個未命名的內聯函數”。lambda表達式的一般形式是

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

  1. capture list -> 捕獲列表(必選)
  2. parameter list -> 參數列表(可選)
  3. function body -> 函數主體(必選)
  4. 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

三點規則:
  1. 若function body中只有一條return語句,則return type可以沒有,返回值類型由return語句推測。
  2. 若無return語句,則返回值類型爲void.
  3. 若除了return語句外還有其它語句,則必須指定返回值的類型,且必須使用尾置返回類型,即"->類型名"的形式。




本專欄目錄
所有內容的目錄


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