C++中function包裝器的應(yīng)用實(shí)例詳解
前言:
在現(xiàn)代 C++ 中,std::function 是一個(gè)非常有用的工具,它使得函數(shù)能夠像對象一樣傳遞、存儲和調(diào)用。隨著 C++11 的到來,std::function 被引入到標(biāo)準(zhǔn)庫中,成為函數(shù)式編程和回調(diào)機(jī)制的核心組件之一。在這篇博客中,我們將深入探討 std::function 的工作原理、應(yīng)用場景及其優(yōu)缺點(diǎn)。
1.什么是 std::function?
std::function 是 C++11 引入的一個(gè)模板類,用于封裝任何可調(diào)用對象(如普通函數(shù)、Lambda 表達(dá)式、函數(shù)指針、成員函數(shù)指針或函數(shù)對象等)。它允許你存儲一個(gè)可調(diào)用對象,并在需要時(shí)調(diào)用它。這使得我們可以更加靈活地編寫代碼,特別是在需要傳遞回調(diào)函數(shù)或異步任務(wù)時(shí),std::function 顯得尤為重要。
std::function 是通過類型擦除實(shí)現(xiàn)的,它可以在運(yùn)行時(shí)動態(tài)地將不同類型的可調(diào)用對象轉(zhuǎn)化為統(tǒng)一的接口。簡單來說,它允許你用一個(gè)通用的對象來代替不同類型的函數(shù)或函數(shù)指針。
2. function 包裝器的原型
std::function在頭文件<functional>
// 類模板原型如下 template <class T> function; // undefined template <class Ret, class... Args> class function<Ret(Args...)>;
模板參數(shù)說明:
Ret: 被調(diào)用函數(shù)的返回類型Args…:被調(diào)用函數(shù)的形參。
3.使用 function 封裝不同類型的函數(shù)對象
#include <iostream>
#include <functional>
#include <string>
using namespace std;
// 普通函數(shù)
void func(int n)
{
cout << "普通函數(shù): " << n << endl;
}
// 仿函數(shù)
struct Func
{
void operator()(int n)
{
cout << "仿函數(shù): " << n << endl;
}
};
// Lambda 表達(dá)式
auto lambda = [](int n) { cout << "Lambda 表達(dá)式: " << n << endl; };
int main()
{
// 使用 std::function 封裝不同類型的函數(shù)
function<void(int)> f;
f = func; // 包裝普通函數(shù)
f(10);
f = Func(); // 包裝仿函數(shù)
f(20);
f = lambda; // 包裝 Lambda 表達(dá)式
f(30);
return 0;
}
代碼分析
我們定義了三個(gè)不同類型的函數(shù):一個(gè)普通函數(shù) func、一個(gè)仿函數(shù) Func 和一個(gè) Lambda 表達(dá)式 lambda。
然后,使用 std::function<void(int)> 來封裝這三種不同類型的函數(shù)對象。
通過調(diào)用包裝后的 f,我們可以統(tǒng)一的方式執(zhí)行這些不同的函數(shù)對象。(適配器)
這種方式使得我們能夠?qū)⒍喾N類型的可調(diào)用對象統(tǒng)一為一個(gè)接口,方便管理和使用。
4.實(shí)際應(yīng)用:
150. 逆波蘭表達(dá)式求值 - 力扣(LeetCode)

解法一:
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> st;
for(auto& to:tokens)
{
if(to=="+"||to=="-"||to=="*"||to=="/")
{
int right=st.top();
st.pop();
int left=st.top();
st.pop();
switch(to[0])
{
case '+':
st.push(left+right);
break;
case '-':
st.push(left-right);
break;
case '*':
st.push(left*right);
break;
case '/':
st.push(left/right);
break;
}
}
else
{
st.push(stoi(to));
}
}
return st.top();
}
};解法二: 利用function包裝器:
class Solution
{
public:
int evalRPN(vector<string>& tokens)
{
// 解題思路:操作數(shù)入棧,遇到操作符,取兩個(gè)數(shù)計(jì)算后,入棧
// 建立映射關(guān)系
unordered_map<string, function<int(int, int)>> hash =
{
{"+", [](int x, int y)->int { return x + y; } },
{"-", [](int x, int y)->int { return x - y; } },
{"*", [](int x, int y)->int { return x * y; } },
{"/", [](int x, int y)->int { return x / y; } },
};
stack<int> s;
for(auto str : tokens)
{
if(str != "+" && str != "-" && str != "*" && str != "/")
s.push(stoi(str));
else
{
// 注意:先獲取 y,再獲取 x
int y = s.top();
s.pop();
int x = s.top();
s.pop();
s.push(hash[str](x, y));
}
}
return s.top();
}
};
function作為C++11的一個(gè)知識,還是非常好用的。??
5. bind 綁定:修改參數(shù)傳遞順序和數(shù)量
bind 是 C++ 標(biāo)準(zhǔn)庫中的一個(gè)函數(shù)模板,它允許我們對函數(shù)參數(shù)進(jìn)行預(yù)先綁定或重新排列,從而生成一個(gè)新的可調(diào)用對象。bind 的強(qiáng)大之處在于,它不僅能夠指定某些參數(shù)的固定值,還能改變參數(shù)傳遞的順序,極大地提高了靈活性。
函數(shù)原型:
template <class Fn, class... Args> bind (Fn&& fn, Args&&... args);
fn 是傳遞的 函數(shù)對象,args 是傳給函數(shù)的 可變參數(shù)包,這里使用了 萬能引用(引用折疊),使其在進(jìn)行模板類型推導(dǎo)時(shí),既能引用左值,也能引用右值。
2.1 使用 bind 綁定修改參數(shù)傳遞順序
#include <iostream>
#include <functional>
using namespace std;
void Func(int a, int b)
{
cout << "Func: " << a << " " << b << endl;
}
int main()
{
// 正常調(diào)用
Func(10, 20);
// 使用 bind 改變參數(shù)順序
auto RFunc = bind(Func, std::placeholders::_2, std::placeholders::_1);
RFunc(10, 20); // 輸出: Func: 20 10
return 0;
}
代碼分析
bind(Func, std::placeholders::_2, std::placeholders::_1) 通過 placeholders::_1 和 placeholders::_2 指定了新的參數(shù)順序,即將原本的第二個(gè)參數(shù)和第一個(gè)參數(shù)交換。
當(dāng)我們調(diào)用 RFunc(10, 20) 時(shí),實(shí)際上是將 20 作為第一個(gè)參數(shù),10 作為第二個(gè)參數(shù)傳遞給 Func。
這種參數(shù)順序的改變,在一些特定的應(yīng)用場景下非常有用,特別是在函數(shù)簽名不一致時(shí),可以方便地進(jìn)行適配。
2.2. bind 綁定:指定特定參數(shù)
bind 還可以用于指定函數(shù)的某些參數(shù)為固定值,從而減少后續(xù)調(diào)用時(shí)需要傳遞的參數(shù)個(gè)數(shù)。
示例代碼:使用 bind 綁定指定特定參數(shù)
#include <iostream>
#include <functional>
using namespace std;
void Func(int a, int b)
{
cout << "Func: " << a << " " << b << endl;
}
int main()
{
// 使用 bind 綁定第一個(gè)參數(shù)
auto RFunc = bind(Func, 100, std::placeholders::_1);
RFunc(20); // 輸出: Func: 100 20
return 0;
}
代碼分析
我們通過 bind(Func, 100, std::placeholders::_1) 將第一個(gè)參數(shù)綁定為固定值 100。
后續(xù)調(diào)用時(shí),我們只需要傳遞第二個(gè)參數(shù) 20,bind 會自動將 100 作為第一個(gè)參數(shù)傳遞給 Func。
2.3. bind 綁定與類成員函數(shù)
bind 還可以用于綁定類成員函數(shù)。對于普通函數(shù),綁定非常簡單,但對于成員函數(shù),我們需要額外注意如何傳遞類的對象或指針。
示例代碼:使用 bind 綁定靜態(tài)成員函數(shù)
#include <iostream>
#include <functional>
using namespace std;
class Test
{
public:
static void funcA(int val)
{
cout << "靜態(tài)成員函數(shù) funcA: " << val << endl;
}
};
int main()
{
// 使用 bind 綁定靜態(tài)成員函數(shù)
auto RFunc = bind(&Test::funcA, std::placeholders::_1);
RFunc(10); // 輸出: 靜態(tài)成員函數(shù) funcA: 10
return 0;
}
代碼分析
對于靜態(tài)成員函數(shù),我們可以直接使用 &Test::funcA 來綁定。
bind 會自動處理函數(shù)的綁定,并返回一個(gè)新的可調(diào)用對象 RFunc,我們可以使用它來調(diào)用函數(shù)。
示例代碼:使用 bind 綁定非靜態(tài)成員函數(shù)
#include <iostream>
#include <functional>
using namespace std;
class Test
{
public:
Test(int n) : _n(n) {}
void funcB(int val)
{
cout << "非靜態(tài)成員函數(shù) funcB: " << val * _n << endl;
}
private:
int _n;
};
int main()
{
Test t(10);
// 使用 bind 綁定非靜態(tài)成員函數(shù)
auto RFunc = bind(&Test::funcB, t, std::placeholders::_1);
RFunc(5); // 輸出: 非靜態(tài)成員函數(shù) funcB: 50
return 0;
}
代碼分析
對于非靜態(tài)成員函數(shù),我們需要提供類的對象 t 作為參數(shù)來綁定。
bind 會將 t 與 &Test::funcB 結(jié)合,并生成一個(gè)新的可調(diào)用對象。
總結(jié):
通過 std::function 和 bind,C++ 提供了強(qiáng)大的函數(shù)包裝和綁定功能,使得我們能夠在不同類型的函數(shù)之間進(jìn)行無縫切換、修改參數(shù)傳遞順序以及綁定特定參數(shù)。這些工具極大地增強(qiáng)了代碼的靈活性和可重用性,特別是在需要對多個(gè)不同函數(shù)進(jìn)行統(tǒng)一管理時(shí),它們提供了非常便捷的解決方案。在實(shí)際開發(fā)中,這些技巧不僅能幫助我們提升編程效率,還能讓代碼更加簡潔和優(yōu)雅。
到此這篇關(guān)于C++中function包裝器應(yīng)用的文章就介紹到這了,更多相關(guān)C++ function包裝器應(yīng)用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
json error: Use of overloaded operator [] is ambiguous錯誤的解決方
今天小編就為大家分享一篇關(guān)于json error: Use of overloaded operator [] is ambiguous錯誤的解決方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-04-04
C語言實(shí)現(xiàn)實(shí)時(shí)鐘表
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)實(shí)時(shí)鐘表,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
C語言中進(jìn)程信號集的相關(guān)操作函數(shù)詳解
這篇文章主要介紹了C語言中進(jìn)程信號集的相關(guān)操作函數(shù)詳解,包括sigismember函數(shù)和sigfillset函數(shù)以及sigemptyset函數(shù)的用法,需要的朋友可以參考下2015-09-09
c++ map索引不存在的key可能導(dǎo)致的后果分析
這篇文章主要介紹了c++ map索引不存在的key可能導(dǎo)致的后果分析,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
Linux?C/C++實(shí)現(xiàn)顯示NIC流量統(tǒng)計(jì)信息
NIC流量統(tǒng)計(jì)信息是由操作系統(tǒng)維護(hù)的,當(dāng)數(shù)據(jù)包通過NIC傳輸時(shí),操作系統(tǒng)會更新相關(guān)的計(jì)數(shù)器,通過讀取這些計(jì)數(shù)器,我們可以獲得關(guān)于網(wǎng)絡(luò)流量的信息,下面我們就來學(xué)習(xí)一下如何通過C/C++實(shí)現(xiàn)顯示NIC流量統(tǒng)計(jì)信息吧2024-01-01
詳解C語言中不同類型的數(shù)據(jù)轉(zhuǎn)換規(guī)則
這篇文章給大家講解不同類型數(shù)據(jù)間的混合運(yùn)算與類型轉(zhuǎn)換,有自動類型轉(zhuǎn)換和強(qiáng)制類型轉(zhuǎn)換,針對每種轉(zhuǎn)換方法小編給大家介紹的非常詳細(xì),需要的朋友參考下吧2021-07-07

