C++11 Lambda 表達(dá)式、std::function 與 std::bind 解析
一、 Lambda 表達(dá)式
1.1 核心概念與語法
- 概念解釋:
- Lambda 表達(dá)式:C++11 引入的一種匿名函數(shù)定義方式,允許在調(diào)用的地方內(nèi)聯(lián)定義函數(shù)邏輯,極大提升了代碼的緊湊性和可讀性。其底層本質(zhì)是編譯器自動(dòng)生成的匿名仿函數(shù)(Functor)類對(duì)象。
- 仿函數(shù)(Functor):又稱函數(shù)對(duì)象,是指重載了函數(shù)調(diào)用運(yùn)算符
operator()的類或結(jié)構(gòu)體實(shí)例。這使得該對(duì)象可以像普通函數(shù)一樣被調(diào)用。
- 筆記:
- 語法模板:
[capture-list] (parameters) mutable -> return-type { function-body }
| 組成部分 | 是否必填 | 說明 |
|---|---|---|
[capture-list] | 必填 | 捕捉列表:控制 Lambda 訪問外部局部變量的方式。 |
(parameters) | 可選 | 參數(shù)列表:與普通函數(shù)一致,無參可省略 ()。 |
mutable | 可選 | 默認(rèn)按值捕捉的變量副本是 const 的,添加此關(guān)鍵字后可修改副本。 |
-> return-type | 可選 | 返回值類型:通??捎删幾g器自動(dòng)推導(dǎo),復(fù)雜邏輯下可顯式指定。 |
{ body } | 必填 | 函數(shù)體:實(shí)現(xiàn)具體邏輯。 |
- 捕捉列表規(guī)則:
[=]:隱式按值捕捉(獲取當(dāng)前作用域所有變量的副本)。[&]:隱式按引用捕捉。[a, &b]:明確指定變量a按值捕捉,變量b按引用捕捉。
- 混合捕捉:第一個(gè)元素必須是
=或&。例如[=, &x]表示除x按引用捕捉外,其余全部按值捕捉。
? 發(fā)散:為什么 Lambda 表達(dá)式默認(rèn)按值捕捉的變量是不可修改的(需要加
mutable)??? 解答:因?yàn)?Lambda 底層會(huì)被編譯器轉(zhuǎn)換為一個(gè)仿函數(shù)類。按值捕捉的變量會(huì)變成該類的成員變量。默認(rèn)情況下,編譯器生成的
operator()是一個(gè)const成員函數(shù),因此無法修改類的成員變量。加上mutable關(guān)鍵字,本質(zhì)上就是去掉了operator()的const限定符。
二、 std::function (多態(tài)函數(shù)包裝器)
2.1 核心概念與底層機(jī)制
- 概念解釋:
- 類型擦除(Type Erasure):一種編程技術(shù),能夠在編譯期抹除對(duì)象的具體類型信息,而在運(yùn)行期對(duì)外提供統(tǒng)一的接口。
std::function通過多態(tài)(虛函數(shù))在底層實(shí)現(xiàn)了類型擦除,使得不同類型的可調(diào)用對(duì)象對(duì)外表現(xiàn)完全一致。 - 模板特化(Template Specialization):C++ 模板機(jī)制之一,允許為特定的數(shù)據(jù)類型提供專門的模板實(shí)現(xiàn)。
std::function的原型就是利用了模板特化來精準(zhǔn)匹配函數(shù)簽名R(Args...)。
- 類型擦除(Type Erasure):一種編程技術(shù),能夠在編譯期抹除對(duì)象的具體類型信息,而在運(yùn)行期對(duì)外提供統(tǒng)一的接口。
- 函數(shù)名:
std::function - 函數(shù)原型:
#include <functional> template< class R, class... Args > class function<R(Args...)>;
- 功能與參數(shù)說明:一個(gè)通用的多態(tài)函數(shù)封裝器。
R表示函數(shù)的返回值類型(Return type),Args...表示可變參數(shù)列表類型(Argument types)。R(Args...)被稱為“函數(shù)簽名”。
2.2 核心價(jià)值與應(yīng)用場(chǎng)景
- 筆記:
- 設(shè)計(jì)示例:
using ioservice_t = std::function<void(std::shared_ptr<Socket> &sock, InetAddr &client)>;- 含義:只要滿足“接收這兩個(gè)參數(shù)并返回
void”的任何代碼邏輯,都可以被賦值給ioservice_t類型。
- 含義:只要滿足“接收這兩個(gè)參數(shù)并返回
- 核心價(jià)值 A:解耦(工程價(jià)值核心):
- 網(wǎng)絡(luò)層(TcpServer):只負(fù)責(zé)基礎(chǔ)建設(shè)(處理并發(fā)、建立連接,“搬磚”)。不關(guān)心連接后做什么。
- 業(yè)務(wù)層(Callback):只負(fù)責(zé)邏輯處理(“大腦”)。不關(guān)心網(wǎng)絡(luò)底層建立機(jī)制。
- 聯(lián)系紐帶:
ioservice_t就是兩者之間的“協(xié)議插座”或“任務(wù)規(guī)格”。 - 核心價(jià)值 B:屏蔽底層差異(類型擦除):
- 統(tǒng)一化四種不同的底層可調(diào)用對(duì)象形式:
- 普通函數(shù):
void MyFunc(std::shared_ptr<Socket> &s, InetAddr &a); - Lambda 表達(dá)式:
[](std::shared_ptr<Socket> &s, InetAddr &a){ ... }; - 仿函數(shù):
struct MyHandler { void operator()(std::shared_ptr<Socket> &s, InetAddr &a); }; - 類成員函數(shù)(需配合
std::bind)。
2.3 復(fù)雜業(yè)務(wù)邏輯的進(jìn)階處理
筆記:
當(dāng)業(yè)務(wù)接口復(fù)雜,或需要額外參數(shù)(如數(shù)據(jù)庫(kù)句柄等)時(shí),有三種標(biāo)準(zhǔn)做法將其適配為 std::function 要求的簽名:
方法一:利用 Lambda 表達(dá)式“捕獲”變量(最現(xiàn)代、簡(jiǎn)潔)
Database db;
server.Start([&db](std::shared_ptr<Socket> &sock, InetAddr &client) {
db.Query(sock->Recv(...)); // 捕獲外部 db 進(jìn)行操作
});
方法二:使用 std::bind 進(jìn)行參數(shù)適配
void SuperService(std::shared_ptr<Socket>& s, InetAddr& a, MyManager* mgr); MyManager manager; // 將 mgr 壓入,生成只接受 2 個(gè)參數(shù)的新對(duì)象 auto service = std::bind(SuperService, std::placeholders::_1, std::placeholders::_2, &manager); server.Start(service);
方法三:封裝成“業(yè)務(wù)類”(仿函數(shù))
class ChatBusiness {
public:
void operator()(std::shared_ptr<Socket> &sock, InetAddr &client) {
Login(); SaveMsg(); // 執(zhí)行內(nèi)部復(fù)雜邏輯
}
private:
void Login(); void SaveMsg();
};
ChatBusiness cb;
server.Start(cb);
一句話總結(jié):std::function 讓服務(wù)器框架不再關(guān)心“做什么”,而只關(guān)心“怎么連”,實(shí)現(xiàn)了一套代碼、百種業(yè)務(wù)的高度復(fù)用(扮演“分揀員”角色)。
三、 std::bind (函數(shù)參數(shù)綁定)
3.1 核心概念與占位符
- 概念解釋:
- 參數(shù)綁定(Bind):通過“綁定”或“重新排列”原有函數(shù)的參數(shù),提前固定部分參數(shù)或調(diào)整參數(shù)順序,從而生成一個(gè)新的可調(diào)用對(duì)象(仿函數(shù))。
- 占位符(Placeholder):定義在
std::placeholders命名空間中(如_1,_2),用于在綁定時(shí)“占位”,代表未來新生成的函數(shù)被調(diào)用時(shí),由調(diào)用者動(dòng)態(tài)傳入的參數(shù)位置。
- 函數(shù)名:
std::bind - 函數(shù)原型:
#include <functional> template< class F, class... Args > /* 返回值類型未命名,通常用 auto 或 std::function 接收 */ bind( F&& f, Args&&... args );
功能與參數(shù)說明:f 是待包裝的可調(diào)用對(duì)象;args 是要綁定的參數(shù)列表,可以是具體數(shù)值(提前固定),也可以是占位符。返回值是一個(gè)臨時(shí)的仿函數(shù)對(duì)象。
3.2 基礎(chǔ)與進(jìn)階用法
- 筆記:
- 前提假設(shè):存在基礎(chǔ)函數(shù)
int Sub(int a, int b) { return a - b; } - 用法 1:調(diào)整參數(shù)順序
// 新函數(shù)的參數(shù) 2 傳給 a,參數(shù) 1 傳給 b auto f1 = std::bind(Sub, std::placeholders::_2, std::placeholders::_1); // f1(10, 5) 實(shí)際執(zhí)行 Sub(5, 10),結(jié)果為 -5
用法 2:調(diào)整個(gè)數(shù)(固定參數(shù) / 局部應(yīng)用)
// a 強(qiáng)制固定為 100,新函數(shù)的參數(shù) 1 傳給 b auto f2 = std::bind(Sub, 100, std::placeholders::_1); // f2(5) 實(shí)際執(zhí)行 Sub(100, 5),結(jié)果為 95
用法 3:綁定類成員函數(shù)(高頻場(chǎng)景)
class Plus {
public:
int plusd(int a, int b) { return a + b; }
};
Plus pd;
auto f = std::bind(&Plus::plusd, &pd, std::placeholders::_1, std::placeholders::_2);
// f(10, 20) 等價(jià)于 pd.plusd(10, 20)- 必須顯式使用
&類名::函數(shù)名。 - 第二個(gè)參數(shù)必須傳入對(duì)象的地址(
&obj)或引用,以填補(bǔ)成員函數(shù)隱含的this指針。 - 使用總結(jié)與建議:
- 接收方式:返回臨時(shí)對(duì)象,建議本地直接用
auto接收;跨函數(shù)傳遞用std::function包裝。 - 值拷貝問題:
std::bind默認(rèn)執(zhí)行值拷貝。如需傳遞引用,必須顯式配合std::ref使用。 - 現(xiàn)代 C++ 建議:C++11 之后,絕大多數(shù)
std::bind的場(chǎng)景都能被 Lambda 替代。Lambda 語法更直觀,且編譯器更容易對(duì)其進(jìn)行內(nèi)聯(lián)優(yōu)化,性能更佳。
? 導(dǎo)師發(fā)散提問:為什么大部分情況下,現(xiàn)代 C++ 提倡用 Lambda 替代
std::bind??? 解答:首先是可讀性,嵌套的
std::bind和大量的_1,_2占位符極難閱讀,而 Lambda 參數(shù)流向清晰;其次是性能,std::bind內(nèi)部機(jī)制復(fù)雜且依賴大量模板元編程,其生成的對(duì)象很難被編譯器徹底內(nèi)聯(lián)優(yōu)化,而 Lambda 會(huì)生成簡(jiǎn)單的局部匿名類,編譯器可以輕易將其內(nèi)聯(lián)展開。
到此這篇關(guān)于C++11 Lambda 表達(dá)式、std::function 與 std::bind 解析的文章就介紹到這了,更多相關(guān)C++11 std::function 與 std::bind內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++實(shí)現(xiàn)接兩個(gè)鏈表實(shí)例代碼
這篇文章主要介紹了C++實(shí)現(xiàn)接兩個(gè)鏈表實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2017-03-03
VC++實(shí)現(xiàn)通過API來查看程序錯(cuò)誤信息的方法
這篇文章主要介紹了VC++實(shí)現(xiàn)通過API來查看程序錯(cuò)誤信息的方法,非常實(shí)用的功能,需要的朋友可以參考下2014-08-08
C語言學(xué)生成績(jī)管理系統(tǒng)設(shè)計(jì)
這篇文章主要為大家詳細(xì)介紹了C語言學(xué)生成績(jī)管理系統(tǒng)設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01

