【C++11】——lambda表達式-創(chuàng)新互聯(lián)

成都創(chuàng)新互聯(lián)于2013年創(chuàng)立,先為汝南等服務建站,汝南等地企業(yè),進行企業(yè)商務咨詢服務。為汝南企業(yè)網站制作PC+手機+微官網三網同步一站式服務解決您的所有建站問題。

目錄

一、lambda表達式的簡介

二、lambda表達式的基本語法

三、lambda表達式的使用方法

四、lambda表達式的底層原理


一、lambda表達式的簡介

lambda表達式就類似于仿函數,相比仿函數要更加的簡潔,我們看一下下面的代碼:

//商品類
struct Goods
{
    string _name; ?// 名字
    double _price; // 價格
    int _evaluate; // 評價
};

在給定的商品類中,如果我們想要通過名字、價格和評價來給商品進行升序或降序。在沒有l(wèi)ambda表達式的時候,通過仿函數就可以實現,代碼如下:

//按價格的升序
struct ComparePriceLess
{
	bool operator()(const Goods& g1, const Goods& g2)
	{
		return g1._price< g2._price;
	}
};

//按價格降序
struct ComparePriceGreater
{
	bool operator()(const Goods& g1, const Goods& g2)
	{
		return g1._price >g2._price;
	}
};

int main()
{
	vectorv = { { "蘋果", 2.1, 300 }, { "香蕉", 3.3, 100 }, { "橙子", 2.2, 1000 }, { "菠蘿", 1.5, 1 } };
	sort(v.begin(), v.end(), ComparePriceLess());    //按價格升序排序
	sort(v.begin(), v.end(), ComparePriceGreater()); //按價格降序排序
	return 0;
}

顯然這樣寫是沒有什么問題,但是,如果你寫的仿函數在取名的時候不是很貼切,導致他人看你寫的仿函數的時候,有可能看不懂,我們來看看lambda表達式寫出來是什么樣子的;

int main()
{
	vectorv = { { "蘋果", 2.1, 300 }, { "香蕉", 3.3, 100 }, { "橙子", 2.2, 1000 }, { "菠蘿", 1.5, 1 } };
	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2)
	{
		return g1._price< g2._price; 
	}); //按價格升序排序

	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2)
	{
		return g1._price >g2._price;
	}); //按價格降序排序

	return 0;
}

這樣一來,每次調用sort函數時只需要傳入一個lambda表達式指明比較方式即可,閱讀代碼的人一看到lambda表達式就知道本次排序的比較方式是怎樣的,提高了代碼的可讀性。?

二、lambda表達式的基本語法
lambda表達式書寫格式:[capture-list] (parameters) mutable ->return-type { statement }
  • [capture-list] : 捕捉列表,該列表總是出現在lambda函數的開始位置,編譯器根據[]來判斷接下來的代碼是否為lambda函數,捕捉列表能夠捕捉上下文中的變量供lambda函數使用。
  • (parameters):參數列表。與普通函數的參數列表一致,如果不需要參數傳遞,則可以 連同()一起省略
  • mutable:默認情況下,lambda函數總是一個const函數,mutable可以取消其常量性。使用該修飾符時,參數列表不可省略(即使參數為空)。
  • ->returntype:返回值類型。用追蹤返回類型形式聲明函數的返回值類型,沒有返回值時此部分可省略。返回值類型明確情況下,也可省略,由編譯器對返回類型進行推導。
  • {statement}:函數體。在該函數體內,除了可以使用其參數外,還可以使用所有捕獲 到的變量。

lambda函數的參數列表和返回值類型都是可選部分,但捕捉列表和函數體是不可省略的,因此最簡單的lambda函數如下:?

int main()
{
    //最簡單的lambda表達式,該lambda表達式沒有任何意義
	[]{}; 

	return 0;
}

捕獲列表說明:

  • [?var?]:表示值傳遞方式捕捉變量var
  • [?=?]:表示值傳遞方式捕獲所有父作用域中的變量(成員函數中包括this)
  • [?&var?]:表示引用傳遞捕捉變量var
  • [?&?]:表示引用傳遞捕捉所有父作用域中的變量(成員函數中包括this)

注意:
  1. 父作用域指的是包含lambda函數的語句塊
  2. 語法上捕捉列表可由多個捕捉項組成,并以逗號分割。比如:[=, &a, &b],以引用傳遞的方式捕捉變量a和b,值傳遞方式捕捉其他所有變量 ;[&,a, this]:值傳遞方式捕捉變量a和this,引用方式捕捉其他變量;
  3. 捕捉列表不允許變量重復傳遞,否則就會導致編譯錯誤。 比如:[=, a]:=已經以值傳遞方式捕捉了所有變量,捕捉a重復
  4. 在塊作用域以外的lambda函數捕捉列表必須為空。
  5. 在塊作用域中的lambda函數僅能捕捉父作用域中局部變量,捕捉任何非此作用域或者非局部變量都會導致編譯報錯。
  6. lambda表達式之間不能相互賦值,即使看起來類型相同。
三、lambda表達式的使用方法

使用lambda表達式進行兩數的交換

int main()
{
	int a = 10, b = 20;
    //這里的“->void”也是可以省略的
	auto Swap = [](int& x, int& y)->void{
		int tmp = x;
		x = y;
		y = tmp;
	};

	Swap(a, b); 

	return 0;
}

使用傳值捕捉所有

int main()
{
	int a = 10, b = 20;
	//傳值捕捉所有
	auto Swap = [=]()mutable {
		int tmp = a;
		a = b;
		b = tmp;
	};

	Swap();

	//傳值捕捉a和b
	auto Swap2 = [a, b]()mutable {
		int tmp = a;
		a = b;
		b = tmp;
	};
	Swap2();

	return 0;
}

這里需要注意,在以傳值捕捉的時候,因為lambda表達式總是一個const函數,mutable可以取消其常量性,此時的圓括號也不可以省略

以引用捕捉?

int main()
{
	int a = 10, b = 20;
	//以引用捕捉所有
	auto Swap = [&]{
		int tmp = a;
		a = b;
		b = tmp;
	};

	Swap();

	//以引用捕捉a和b
	auto Swap2 = [&a, &b]{
		int tmp = a;
		a = b;
		b = tmp;
	};
	Swap2();

	//以引用捕捉a、以傳值捕捉b
	auto Swap3 = [&a, b]()mutable {
		int tmp = a;
		a = b;
		b = tmp;
	};
	Swap3();

	return 0;
}

lambda表達式之間不能相互賦值,即使看起來類型相同

void (*PF)();
int main()
{
	auto f1 = [] {cout<< "hello world"<< endl; };
	auto f2 = [] {cout<< "hello world"<< endl; };

	//f1 = f2; ? // 編譯失敗--->提示找不到operator=()

	// 但允許使用一個lambda表達式拷貝構造一個新的副本
	auto f3(f2);
	f3();

	// 可以將lambda表達式賦值給相同類型的函數指針
	PF = f2;
	PF();

	return 0;
}
四、lambda表達式的底層原理

函數對象,又稱為仿函數,即可以想函數一樣使用的對象,就是在類中重載了operator()運算符的類對象。

class Rate
{
public:
	Rate(double rate) : _rate(rate)
	{}

	double operator()(double money, int year)
	{
		return money * _rate * year;
	}

private:
	double _rate;
};

int main()
{
	// 函數對象
	double rate = 0.49;
	Rate r1(rate);
	r1(10000, 2);

	// lamber
	auto r2 = [=](double monty, int year)->double {return monty * rate * year;};
	r2(10000, 2);

	return 0;
}
函數對象將rate作為其成員變量,在定義對象時給出初始值即可,lambda表達式通過捕獲列表可以直接將該變量捕獲到。

lambda表達式底層的處理方式和仿函數是一樣的,在VS下,lambda表達式在底層會被處理為函數對象,該函數對象對應的類名叫做。就算是兩個相同的lambda表達式,它們的uuid也是不同的;

你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網查看詳情吧

當前標題:【C++11】——lambda表達式-創(chuàng)新互聯(lián)
網頁地址:http://bm7419.com/article10/cdgogo.html

成都網站建設公司_創(chuàng)新互聯(lián),為您提供品牌網站制作、網頁設計公司、ChatGPT、虛擬主機、電子商務、標簽優(yōu)化

廣告

聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

手機網站建設