最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++11 lambda表達(dá)式與包裝器function與bind詳解

 更新時(shí)間:2026年05月28日 09:18:13   作者:Sunday不上發(fā)條  
這段文章詳細(xì)介紹了C++11中Lambda表達(dá)式和std::function及std::bind的應(yīng)用,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧

一、lambda表達(dá)式

1.1 概念

C++11 引入的 Lambda 表達(dá)式是一種就地定義的匿名函數(shù)對(duì)象。它允許你在需要函數(shù)的地方直接寫(xiě)一段邏輯,而不必提前定義一個(gè)命名函數(shù)或手寫(xiě)一個(gè)完整的仿函數(shù)類(lèi)。
在學(xué)習(xí)lambda表達(dá)式之前,我們的使用的可調(diào)用對(duì)象只有函數(shù)指針仿函數(shù)對(duì)象,函數(shù)指針的類(lèi)型定義起來(lái)比較麻煩,仿函數(shù)要定義一個(gè)類(lèi)(重載()),相對(duì)會(huì)比較麻煩。使用lambda去定義可調(diào)用對(duì)象,既簡(jiǎn)單又方便。
與普通函數(shù)不同,lambda表達(dá)式可以在函數(shù)內(nèi)部實(shí)現(xiàn)。
語(yǔ)法格式:

[捕捉列表](參數(shù))-> return type {函數(shù)體}

舉個(gè)簡(jiǎn)單的例子:

auto f = [](int a, int b) -> int { return a + b; };
cout << f(2, 3) << endl;

說(shuō)明:

  • 開(kāi)頭的 [ ]必須要寫(xiě),因?yàn)榫幾g器根據(jù)[ ]來(lái)判別其為lambda表達(dá)式;
  • ()即為參數(shù)列表,如果不需要參數(shù),()可以省略;
  • -> return type:返回值類(lèi)型,也可以省略,編譯器會(huì)自動(dòng)推導(dǎo);
  • { }即函數(shù)體,與普通函數(shù)一樣。

1.2 捕捉列表

顧名思義,就是將函數(shù)體中會(huì)用到的變量,對(duì)象等進(jìn)行抓取,使得其在函數(shù)體內(nèi)部可用。

void test()
{
	int a = 2, b = 3;
	auto Add = [a, b]() {return a + b; };
	cout << Add() << endl; // 調(diào)用
}

那么捕捉有什么講究呢?具體有四種捕捉方式:

  • 值捕捉
    • 我們?cè)谏厦嬷苯訉⒆兞棵驅(qū)ο笤诓蹲搅斜聿蹲?,就是值捕捉?/li>
  • 引用捕捉
    • 引用捕捉就是在變量前加 &
void test()
{
	int a = 2, b = 3;
	auto Add = [&a, &b]() {return a + b; };
	cout << Add() << endl; // 調(diào)用
}
  • 顯示捕捉
    • 我們?cè)诓蹲搅斜?,直接?xiě)明要捕捉的變量或?qū)ο缶褪秋@示捕捉。顯示捕捉時(shí)既可以值捕捉,也可以引用捕捉,同樣也可以在一個(gè)捕捉列表中同時(shí)出現(xiàn),值捕捉和引用捕捉。
  • 隱式捕捉
    • 隱式捕捉有隱式值捕捉,即直接在捕捉列表中寫(xiě)一個(gè) =;隱式引用捕捉,即在捕捉列表直接寫(xiě)一個(gè) &。

需要注意:

在用到隱式捕捉時(shí),= 或 & 必須寫(xiě)在捕捉列表最前面,兩者不能同時(shí)出現(xiàn)。如果此時(shí)想混合捕捉,且前面已經(jīng)是 =,那么后面必須全部是引用捕捉;同理,如果前面已經(jīng)是 &,那么后面必須全部是值捕捉。

void test()
{
	int a = 2, b = 3, c = 4;
	auto Add1 = [=]() {return a + b + c; }; // 隱式值捕捉
	auto Add2 = [&]() {return a + b + c; }; // 隱式引用捕捉
	// 混合捕捉
	auto Add3 = [=, &b]() {return a + b + c; }; 
	auto Add4 = [&, c]() {return a + b + c; }; 
	// 錯(cuò)誤示范:隱式值捕捉,后面又顯示值捕捉(重復(fù))
	// auto Add2 = [=, b, c]() {return a + b + c; }; 
}

細(xì)節(jié)補(bǔ)充:
默認(rèn)情況下,值捕捉是被const修飾的,也就是說(shuō)值捕捉的過(guò)來(lái)的對(duì)象不能修改,mutable加在參數(shù)列表的后面可以取消其常量性,也就說(shuō)使用該修飾符后,值捕捉的對(duì)象就可以修改了,但是修改還是形參對(duì)象,不會(huì)影響實(shí)參。使用該修飾符后,參數(shù)列表不可省略(即使參數(shù)為空)。
引用捕捉的對(duì)象可以修改。

int main()
{
	int a = 1, b = 1, c = 1, d = 1;
	auto f = [a, b, &c, &d]() {
		// a++; // 報(bào)錯(cuò)
		// b++; // 報(bào)錯(cuò)
		c++;
		d++;
	};
	f(); // 調(diào)用
	cout << "c = " << c << ", d = " << d << endl;
	return 0;
}

int main()
{
	int a = 1, b = 1, c = 1, d = 1;
	auto f = [a, b, &c, &d]() mutable {
		a++; 
		b++; 
		return a + b;
	};
	cout << f() << endl; // 調(diào)用
	// 并不改變實(shí)參
	cout << "a = " << a << ", b = " << b << endl;
	return 0;
}


對(duì)于全局變量和靜態(tài)局部變量不需要捕捉,lambda表達(dá)式中可以直接使用。這也意味著lambda表達(dá)式如果定義在全局位置,捕捉列表必須為空。

1.3 lambda的應(yīng)用

對(duì)于需要自定義排序的類(lèi)對(duì)象,我們不再需要重載operator(),而是直接用lambda表達(dá)式。

#include <vector>
#include <algorithm>
#include <string>
struct Product 
{
	std::string _name;
	double _price;
	int _stock;
	Product(std::string name, double price, int stock)
		:_name(name),
		_price(price),
		_stock(stock)
	{ }
};
struct Compare
{
	bool operator()(const Product& p1, const Product& p2)
	{
		return p1._price < p2._price;
	}
};
int main()
{
	std::vector<Product> products = {
	{"iPhone", 5999.0, 50},
	{"MacBook", 12999.0, 20},
	{"AirPods", 1299.0, 200}
	};
	// 重載operator()
	std::sort(products.begin(), products.end(), Compare());
	// lambda表達(dá)式:按價(jià)格降序
	std::sort(products.begin(), products.end(),
		[](const Product& a, const Product& b) {
			return a._price > b._price;
		});
	return 0;
}

1.4 lambda原理

其實(shí)就是編譯器在底層將我們寫(xiě)的lambda表達(dá)式轉(zhuǎn)換成了一個(gè)仿函數(shù),實(shí)際上并沒(méi)有所謂的lambda表達(dá)式。

auto f = [x, &y](int a) -> int { return x + a + y; };
// 上面的 Lambda,編譯器會(huì)翻譯成類(lèi)似下面的類(lèi):
class __lambda_unique_id {          // 編譯器生成的唯一類(lèi)名
    int x;                          // 值捕獲的成員(拷貝)
    int& y;                         // 引用捕獲的成員(引用)
public:
    __lambda_unique_id(int _x, int& _y) : x(_x), y(_y) {}
    int operator()(int a) const {   // 函數(shù)調(diào)用運(yùn)算符
        return x + a + y;
    }
};
// 實(shí)際調(diào)用時(shí):
// auto f = __lambda_unique_id(x, y);
// f(5);  // 等價(jià)于 f.operator()(5);

二、包裝器

2.1 function

什么是function,就是將具有相同類(lèi)型返回值,參數(shù)列表的可調(diào)用對(duì)象進(jìn)行包裝,讓可調(diào)用對(duì)象對(duì)外呈現(xiàn)一種類(lèi)型,其頭文件為 <functional>。可調(diào)用對(duì)象有4個(gè):函數(shù)指針,仿函數(shù)lambdabind,bind是什么我們下面介紹?。?!

四種可調(diào)用對(duì)象,四種完全不同的類(lèi)型:

int plain_func(int, int) { return 0; }            // 函數(shù)指針類(lèi)型:int(*)(int,int)
struct Functor { int operator()(int, int) {} };   // 仿函數(shù)類(lèi)型:Functor
auto lambda = [](int, int) { return 0; };         // lambda類(lèi)型:編譯器生成的匿名類(lèi)
auto bound = std::bind(plain_func, _1, _2);       // bind類(lèi)型:std::_Bind<...>

std::function可以包裝存儲(chǔ)這些對(duì)象,這些對(duì)象成為function的目標(biāo)。若std::function不含目標(biāo),則稱(chēng)它為空。調(diào)用空std::function的目標(biāo)就會(huì)導(dǎo)致拋出std::bad_function_call異常。
function的用法:

std::function<返回類(lèi)型(參數(shù)類(lèi)型列表)> f;

所以對(duì)于上面的四個(gè)可調(diào)用對(duì)象,就可以進(jìn)行統(tǒng)一包裝:

std::function<int(int,int)> f1 = plain_func;   // ?
std::function<int(int,int)> f2 = Functor();    // ?
std::function<int(int,int)> f3 = lambda;       // ?
std::function<int(int,int)> f4 = bound;        // ?

應(yīng)用場(chǎng)景:

用function對(duì)象調(diào)用成員函數(shù):
痛點(diǎn):由于成員函數(shù)第一個(gè)參數(shù)默認(rèn)為this指針,當(dāng)我們將成員函數(shù)直接賦值給function對(duì)象就會(huì)報(bào)錯(cuò)。
解決:lambda捕捉this。

class A
{
public:
	int Add(int a, int b)
	{
		return a + b;
	}
};
int main()
{
	A a;
	// 想要調(diào)用成員函數(shù)
	// func_t func = a.Add(2, 3); // 報(bào)錯(cuò)
	// 解決:
	std::function<int(int, int)> func = [&a](int x, int y) {
		return a.Add(x, y); };
	cout << func(2, 3) << endl;
	return 0;
}

2.2 bind

std::bind也是一個(gè)可調(diào)用對(duì)象的包裝器,相當(dāng)于函數(shù)適配器,其頭文件也是 <functional>。有什么特點(diǎn)呢?
它解決的核心問(wèn)題:固定部分參數(shù),留下部分參數(shù)延遲傳入。
bind用法:

auto newCall = bind(Call, arg_list);
// 如果想要調(diào)用類(lèi)A中的成員函數(shù)Call
auto newCall = bind(&A::Call, arg_list);
// 注意:格式必須是&類(lèi)名::成員函數(shù)名

其中newCall本身是一個(gè)可調(diào)用對(duì)象,arg_list是一個(gè)逗號(hào)分隔的參數(shù)列表,對(duì)應(yīng)給定的Call的參數(shù)。當(dāng)我們調(diào)用newCall時(shí),newCall會(huì)調(diào)用Call,并傳給它arg_list中的參數(shù)。
為什么說(shuō)bind支持固定參數(shù)呢?
arg_list中的參數(shù)可能包含形如_n的名字,其中n是一個(gè)整數(shù),這些參數(shù)是占位符,表示newCall的參數(shù),它們占據(jù)了傳遞給newCall的參數(shù)的位置。數(shù)值n表示生成的可調(diào)用對(duì)象中參數(shù)的位置:_1為Call的第一個(gè)參數(shù),_2為第二個(gè)參數(shù),以此類(lèi)推。_1/_2/_3…這些占位符放到placeholders的一個(gè)命名空間中。

int Sub(int x, int y) { return (x - y) * 10; }
void test01()
{
	auto f = bind(Sub, _1, _2);
	cout << f(2, 3) << endl;
}
void test02()
{
	auto f = bind(Sub, _2, _1); // 調(diào)整參數(shù)順序
	cout << f(2, 3) << endl;
}

常用場(chǎng)景一:調(diào)整參數(shù)個(gè)數(shù)(綁定個(gè)別參數(shù))

此時(shí),對(duì)于一些固定不變的參數(shù),就不需要再傳了?。?!

void test03()
{
	auto f1 = bind(Sub, 5, _1);
	cout << f1(3) << endl;
	auto f2 = bind(Sub, _1, 5);
	cout << f2(3) << endl;
}

常用場(chǎng)景二:成員函數(shù)調(diào)用

struct A
{
	int Sub(int a, int b) { return (a - b) * 10; }
};
void Test()
{
	A a;
	auto f1 = bind(&A::Sub, &a, _1, _2);
	// function包裝
	std::function<int(int, int)>  f2 = bind(&A::Sub, &a, _1, _2);
	cout << f1(2, 3) << endl;
	cout << f2(5, 2) << endl;
}

std::bind 綁定成員函數(shù)時(shí),把對(duì)象指針/引用作為第一個(gè)參數(shù)傳入,就填上了 this 的位置,生成的可調(diào)用對(duì)象不再需要外部提供 this,編譯器視角是 返回類(lèi)型(類(lèi)名, 參數(shù)列表)*,同樣可以解決我們調(diào)用成員函數(shù)時(shí)this指針的問(wèn)題。

這些特性在未來(lái)寫(xiě)代碼的過(guò)程中其實(shí)非常常見(jiàn),也很實(shí)用,希望能夠幫助到大家,上面其實(shí)就有我所遇到的場(chǎng)景,如果再有什么實(shí)用的場(chǎng)景我也會(huì)及時(shí)地補(bǔ)充。

到此這篇關(guān)于C++11 lambda表達(dá)式與包裝器function與bind詳解的文章就介紹到這了,更多相關(guān)C++11 lambda表達(dá)式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語(yǔ)言動(dòng)態(tài)內(nèi)存管理分析總結(jié)

    C語(yǔ)言動(dòng)態(tài)內(nèi)存管理分析總結(jié)

    C語(yǔ)言中開(kāi)辟內(nèi)存有很多種方式,目前我們最常用的也就是數(shù)組,但數(shù)組是在我們用到他之前就得設(shè)定好它的長(zhǎng)度,有時(shí)很不方便。隨意我們來(lái)探究動(dòng)態(tài)內(nèi)存管理
    2021-11-11
  • Windows配置VSCode+CMake+Ninja+Boost.Test的C++開(kāi)發(fā)環(huán)境(教程詳解)

    Windows配置VSCode+CMake+Ninja+Boost.Test的C++開(kāi)發(fā)環(huán)境(教程詳解)

    這篇文章主要介紹了Windows配置VSCode+CMake+Ninja+Boost.Test的C++開(kāi)發(fā)環(huán)境,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-05-05
  • Qt簡(jiǎn)單編程實(shí)現(xiàn)UDP通訊

    Qt簡(jiǎn)單編程實(shí)現(xiàn)UDP通訊

    UDP數(shù)據(jù)報(bào)協(xié)議是一個(gè)面向無(wú)連接的傳輸層報(bào)文協(xié)議,它簡(jiǎn)單易用,不存在?TCP協(xié)議“粘包”的問(wèn)題,下面我們就來(lái)看看如何使用qt簡(jiǎn)單實(shí)現(xiàn)UDP通訊吧
    2024-04-04
  • c++ CRTP模式的使用小結(jié)

    c++ CRTP模式的使用小結(jié)

    CRTP是C++中一種高級(jí)的模板編程技術(shù),它通過(guò)將派生類(lèi)作為基類(lèi)的模板參數(shù)來(lái)實(shí)現(xiàn)編譯期多態(tài),本文就來(lái)介紹一下c++ CRTP模式的使用小結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2026-03-03
  • C語(yǔ)言strcat函數(shù)詳解:字符串追加的利器

    C語(yǔ)言strcat函數(shù)詳解:字符串追加的利器

    strcat函數(shù)用于將源字符串追加到目標(biāo)字符串的末尾,并返回一個(gè)指向目標(biāo)字符串的指針,它可以實(shí)現(xiàn)字符串的拼接操作
    2024-08-08
  • 在Ubuntu中安裝VSCode并配置C/C++開(kāi)發(fā)環(huán)境的方法步驟

    在Ubuntu中安裝VSCode并配置C/C++開(kāi)發(fā)環(huán)境的方法步驟

    這篇文章主要介紹了在Ubuntu中安裝VSCode并配置C/C++開(kāi)發(fā)環(huán)境的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • C++調(diào)用python(執(zhí)行py文件)的全過(guò)程

    C++調(diào)用python(執(zhí)行py文件)的全過(guò)程

    這篇文章主要給大家介紹了關(guān)于C++調(diào)用python(執(zhí)行py文件)的相關(guān)資料,文中通過(guò)圖文以及實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-12-12
  • C語(yǔ)言實(shí)現(xiàn)單鏈表的示例詳解

    C語(yǔ)言實(shí)現(xiàn)單鏈表的示例詳解

    給需要考研的同學(xué)一個(gè)參考,單鏈表作為常見(jiàn)數(shù)據(jù)結(jié)構(gòu)的一種,這里記錄C語(yǔ)言實(shí)現(xiàn)單鏈表,文章通過(guò)代碼示例介紹的非常詳細(xì),具有一頂?shù)膮⒖純r(jià)值,需要的朋友可以參考下
    2023-09-09
  • VC++植物大戰(zhàn)僵尸中文版修改器實(shí)現(xiàn)代碼

    VC++植物大戰(zhàn)僵尸中文版修改器實(shí)現(xiàn)代碼

    這篇文章主要介紹了VC++植物大戰(zhàn)僵尸中文版修改器實(shí)現(xiàn)代碼,可實(shí)現(xiàn)植物大戰(zhàn)僵尸中的無(wú)限陽(yáng)光與無(wú)冷卻時(shí)間功能,需要的朋友可以參考下
    2015-04-04
  • C++版本基于ros將文件夾中的圖像轉(zhuǎn)換為bag包

    C++版本基于ros將文件夾中的圖像轉(zhuǎn)換為bag包

    這篇文章主要介紹了C++版本基于ros將文件夾中的圖像轉(zhuǎn)換為bag包,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-01-01

最新評(píng)論

汉阴县| 韶关市| 栾城县| 远安县| 临泉县| 台南市| 杭州市| 丰城市| 普洱| 蚌埠市| 屯昌县| 临夏县| 明水县| 资源县| 桐梓县| 新龙县| 德江县| 永顺县| 雷波县| 西乡县| 密云县| 乌鲁木齐县| 平原县| 泗洪县| 平陆县| 山东| 尼玛县| 龙川县| 吉安市| 万安县| 顺义区| 色达县| 开封市| 新宾| 化德县| 曲松县| 周宁县| 历史| 沙洋县| 逊克县| 福海县|