C++中function包裝器的應(yīng)用實例詳解
前言:
在現(xiàn)代 C++ 中,std::function
是一個非常有用的工具,它使得函數(shù)能夠像對象一樣傳遞、存儲和調(diào)用。隨著 C++11 的到來,std::function
被引入到標(biāo)準(zhǔn)庫中,成為函數(shù)式編程和回調(diào)機制的核心組件之一。在這篇博客中,我們將深入探討 std::function
的工作原理、應(yīng)用場景及其優(yōu)缺點。
1.什么是 std::function?
std::function
是 C++11 引入的一個模板類,用于封裝任何可調(diào)用對象(如普通函數(shù)、Lambda 表達式、函數(shù)指針、成員函數(shù)指針或函數(shù)對象等)。它允許你存儲一個可調(diào)用對象,并在需要時調(diào)用它。這使得我們可以更加靈活地編寫代碼,特別是在需要傳遞回調(diào)函數(shù)或異步任務(wù)時,std::function
顯得尤為重要。
std::function
是通過類型擦除實現(xiàn)的,它可以在運行時動態(tài)地將不同類型的可調(diào)用對象轉(zhuǎn)化為統(tǒng)一的接口。簡單來說,它允許你用一個通用的對象來代替不同類型的函數(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 表達式 auto lambda = [](int n) { cout << "Lambda 表達式: " << n << endl; }; int main() { // 使用 std::function 封裝不同類型的函數(shù) function<void(int)> f; f = func; // 包裝普通函數(shù) f(10); f = Func(); // 包裝仿函數(shù) f(20); f = lambda; // 包裝 Lambda 表達式 f(30); return 0; }
代碼分析
我們定義了三個不同類型的函數(shù):一個普通函數(shù) func
、一個仿函數(shù) Func
和一個 Lambda 表達式 lambda
。
然后,使用 std::function<void(int)>
來封裝這三種不同類型的函數(shù)對象。
通過調(diào)用包裝后的 f,我們可以統(tǒng)一的方式執(zhí)行這些不同的函數(shù)對象。(適配器)
這種方式使得我們能夠?qū)⒍喾N類型的可調(diào)用對象統(tǒng)一為一個接口,方便管理和使用。
4.實際應(yīng)用:
解法一:
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ù)入棧,遇到操作符,取兩個數(shù)計算后,入棧 // 建立映射關(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的一個知識,還是非常好用的。??
5. bind 綁定:修改參數(shù)傳遞順序和數(shù)量
bind
是 C++ 標(biāo)準(zhǔn)庫中的一個函數(shù)模板,它允許我們對函數(shù)參數(shù)進行預(yù)先綁定或重新排列,從而生成一個新的可調(diào)用對象。bind
的強大之處在于,它不僅能夠指定某些參數(shù)的固定值,還能改變參數(shù)傳遞的順序,極大地提高了靈活性。
函數(shù)原型:
template <class Fn, class... Args> bind (Fn&& fn, Args&&... args);
fn
是傳遞的 函數(shù)對象,args
是傳給函數(shù)的 可變參數(shù)包,這里使用了 萬能引用(引用折疊),使其在進行模板類型推導(dǎo)時,既能引用左值,也能引用右值。
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ù)順序,即將原本的第二個參數(shù)和第一個參數(shù)交換。
當(dāng)我們調(diào)用 RFunc(10, 20) 時,實際上是將 20 作為第一個參數(shù),10 作為第二個參數(shù)傳遞給 Func。
這種參數(shù)順序的改變,在一些特定的應(yīng)用場景下非常有用,特別是在函數(shù)簽名不一致時,可以方便地進行適配。
2.2. bind 綁定:指定特定參數(shù)
bind
還可以用于指定函數(shù)的某些參數(shù)為固定值,從而減少后續(xù)調(diào)用時需要傳遞的參數(shù)個數(shù)。
示例代碼:使用 bind
綁定指定特定參數(shù)
#include <iostream> #include <functional> using namespace std; void Func(int a, int b) { cout << "Func: " << a << " " << b << endl; } int main() { // 使用 bind 綁定第一個參數(shù) auto RFunc = bind(Func, 100, std::placeholders::_1); RFunc(20); // 輸出: Func: 100 20 return 0; }
代碼分析
我們通過 bind(Func, 100, std::placeholders::_1)
將第一個參數(shù)綁定為固定值 100
。
后續(xù)調(diào)用時,我們只需要傳遞第二個參數(shù) 20
,bind
會自動將 100
作為第一個參數(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ù)的綁定,并返回一個新的可調(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é)合,并生成一個新的可調(diào)用對象。
總結(jié):
通過 std::function
和 bind
,C++ 提供了強大的函數(shù)包裝和綁定功能,使得我們能夠在不同類型的函數(shù)之間進行無縫切換、修改參數(shù)傳遞順序以及綁定特定參數(shù)。這些工具極大地增強了代碼的靈活性和可重用性,特別是在需要對多個不同函數(shù)進行統(tǒng)一管理時,它們提供了非常便捷的解決方案。在實際開發(fā)中,這些技巧不僅能幫助我們提升編程效率,還能讓代碼更加簡潔和優(yōu)雅。
到此這篇關(guān)于C++中function包裝器應(yīng)用的文章就介紹到這了,更多相關(guān)C++ function包裝器應(yīng)用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
c++中臨時變量不能作為非const的引用參數(shù)的方法
下面小編就為大家?guī)硪黄猚++中臨時變量不能作為非const的引用參數(shù)的方法。小編覺得挺不錯的現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-01-01詳解C++中typedef 和 #define 的區(qū)別
這篇文章主要介紹了C++中typedef 與 #define 的區(qū)別,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-09-09