C++11中的包裝器實(shí)戰(zhàn)案例
引言
在C++中,可調(diào)用對(duì)象類(lèi)型五花八門(mén)(函數(shù)指針、仿函數(shù)、lambda表達(dá)式、類(lèi)成員函數(shù)等),它們的邏輯功能十分相似,但是類(lèi)型差異巨大,導(dǎo)致代碼聲明繁瑣、接口適配困難、擴(kuò)展性不足。而C++11通過(guò)引入
std::function包裝器,抹平了不同類(lèi)型間的差異;引入std::bind包裝器,靈活調(diào)整參數(shù)列表,以適配各種接口。
1.std::function
1.1.什么是std::function
std::function是C++11提供的類(lèi)模板包裝器,定義在<functional>頭文件中,核心作用是消除不同可調(diào)用對(duì)象的類(lèi)型差異。無(wú)論是普通函數(shù)、lambda還是仿函數(shù),都能被std::function包裝成同一類(lèi)型。
template <class Ret, class... Args> class function<Ret(Args...)>;
Ret:可調(diào)用對(duì)象的返回值類(lèi)型Args...:可調(diào)用對(duì)象的參數(shù)列表
1.2.核心用法
1.2.1.包裝普通函數(shù)
普通函數(shù)是最基礎(chǔ)的可調(diào)用對(duì)象:
代碼示例:
#include <iostream>
#include <functional>
using namespace std;
int add(int a, int b)
{
return a + b;
}
int main()
{
//包裝add函數(shù),類(lèi)型匹配int<int, int>
function<int(int, int)> func_add = add;
cout << "1 + 2 = " << func_add(1, 2) << endl;
return 0;
}運(yùn)行結(jié)果:

1.2.2.包裝仿函數(shù)
仿函數(shù)是重載operator()的類(lèi)實(shí)例
代碼示例:
#include <iostream>
#include <functional>
using namespace std;
struct Sub {
int operator()(int a, int b)
{
return a - b;
}
};
int main()
{
function<int(int, int)> func_sub = Sub();
cout << "5 - 3 = " << func_sub(5, 3) << endl;
return 0;
}運(yùn)行結(jié)果:

1.2.3.包裝lambda表達(dá)式
lambda是匿名函數(shù)對(duì)象,function能直接與之匹配
代碼示例:
#include <iostream>
#include <functional>
using namespace std;
int main()
{
function<int(int, int)> func_mul = [](int a, int b) {return a * b;};
cout << "3 * 4 = " << func_mul(3, 4) << endl;
return 0;
}運(yùn)行結(jié)果:

1.2.4.包裝類(lèi)成員函數(shù)
包裝類(lèi)成員函數(shù)需要額外處理this指針,function需在參數(shù)列表中顯式聲明this對(duì)應(yīng)的對(duì)象類(lèi)型(指針或引用);
代碼示例:
#include <iostream>
#include <functional>
using namespace std;
class Divide {
public:
//非靜態(tài)成員函數(shù),參數(shù)隱含this指針
double div(double a, double b)
{
return a / b;
}
//靜態(tài)成員函數(shù),不含this指針
static double div_static(double a, double b)
{
return a / b;
}
};
int main()
{
Divide d;
//包裝非靜態(tài)成員函數(shù),包含this指針
function<double(Divide*, double, double)> func_div = &Divide::div;//非靜態(tài)成員函數(shù)必須取地址,不能隱式類(lèi)型轉(zhuǎn)換
cout << "func_div: " << "12.2 / 2 = " << func_div(&d, 12.2, 2) << endl;
//包裝靜態(tài)成員函數(shù),不包含this指針
function<double(double, double)> func_stat_div = Divide::div_static;//取地址可加可不加
cout << "func_stat_div: " << "12.2 / 2 = " << func_stat_div(12.2, 2) << endl;
return 0;
}運(yùn)行結(jié)果:

1.2.5.空包裝器
若std::function是空包裝器(未綁定任何可調(diào)用對(duì)象),調(diào)用時(shí)會(huì)拋異常(std::bad_function_call),注意捕獲。
代碼示例:
#include <iostream>
#include <functional>
using namespace std;
int main()
{
function<int(int, int)> func_empty;
try {
func_empty(3, 4);
}
catch (const bad_function_call& e) {
cout << "error: " << e.what() << endl;
}
return 0;
}運(yùn)行結(jié)果:

1.3.什么時(shí)候適合用std::function
- 作為容器元素:如
map<string,function<Arg...>>,實(shí)現(xiàn)字符串-函數(shù)映射。 - 作為函數(shù)參數(shù)/返回值:傳遞回調(diào)函數(shù)時(shí),不需要關(guān)注函數(shù)的具體類(lèi)型(函數(shù)指針/仿函數(shù)/lambda),匹配函數(shù)簽名(返回值類(lèi)型、參數(shù)類(lèi)型和數(shù)量)即可。
- 簡(jiǎn)化類(lèi)型聲明:替代復(fù)雜的函數(shù)指針類(lèi)型,如:
int(*)(int ,int),代碼更簡(jiǎn)潔。
2.std::bind
2.1.什么是std::bind
std::bind是C++11提供的函數(shù)模板,定義在<functional>頭文件中,核心作用是調(diào)整可調(diào)用對(duì)象的參數(shù)列表(綁定固定參數(shù)、重新排序參數(shù))
//simple(1) template <class Fn, class... Args> /* unspecified */ bind (Fn&& fn, Args&&... args); //with return type (2) template <class Ret, class Fn, class... Args> /* unspecified */ bind (Fn&& fn, Args&&... args);
一般形式:auto newCallable = bind(callable, arg_list)
- callable:原可調(diào)用對(duì)象
- arg_list:參數(shù)列表
- 參數(shù)列表中,
placeholders::_n(如_1、_2)是占位符,表示新函數(shù)的第n個(gè)參數(shù),未用占位符的參數(shù)會(huì)被“固定綁定”。
2.2.核心用法
2.2.1.綁定固定參數(shù)(減少參數(shù))
假設(shè)我們有一個(gè)計(jì)算乘法的函數(shù)mul,如果我們想固定其中一個(gè)因數(shù)a為100, 只用輸入另一個(gè)因數(shù)b,此時(shí)可用bind實(shí)現(xiàn)
代碼示例:
#include <iostream>
#include <functional>
using namespace std;
using namespace placeholders;
int mul(int a, int b)
{
return a * b;
}
int main()
{
//綁定_a == 100, 新函數(shù)第一個(gè)參數(shù)_1傳給b
auto mul_fixed_a = bind(mul, 100, _1);
cout << "100 * 5 = " << mul_fixed_a(5) << endl;
////綁定_b == 200, 新函數(shù)第一個(gè)參數(shù)_1傳給a
auto sub_fixed_b = bind(mul, _1, 200);
cout << "3 * 200 = " << mul_fixed_a(3) << endl;
return 0;
}運(yùn)行結(jié)果:

2.2.2.重排參數(shù)順序
如果要調(diào)整函數(shù)參數(shù)順序,可以通過(guò)調(diào)整占位符順序?qū)崿F(xiàn)
代碼示例:
#include <iostream>
#include <functional>
using namespace std;
using namespace placeholders;
int sub(int a, int b)
{
return a - b;
}
int main() {
// 原函數(shù)是 a - b,重排后變成 b - a(_2 是新函數(shù)第2個(gè)參數(shù),_1 是第1個(gè))
auto sub_swap = bind(sub, _2, _1);
cout << "5 - 10 = " << sub_swap(10, 5) << endl; // 輸出:(5-10)*10=-50
return 0;
}運(yùn)行結(jié)果:

2.2.3.結(jié)合成員函數(shù)使用
非靜態(tài)成員函數(shù)中參數(shù)包含隱藏的this指針,因此bind綁定時(shí)需要包含該類(lèi)的引用或指針參數(shù)
代碼示例:
#include <iostream>
#include <functional>
using namespace std;
using namespace placeholders;
class Calculator {
public:
double multiply(double a, double b) {
return a * b;
}
};
int main() {
Calculator calc;
// 綁定 calc 作為 this 指針,_1 和 _2 是新函數(shù)的兩個(gè)參數(shù)
auto calc_mul = bind(&Calculator::multiply, &calc, _1, _2);
cout << "3 * 4 = " << calc_mul(3, 4) << endl; // 輸出:12
return 0;
}運(yùn)行結(jié)果:

2.3.什么時(shí)候適合用std::bind
- 適配參數(shù)不匹配的接口:比如一個(gè)第三方庫(kù)函數(shù)需要傳三個(gè)參數(shù),但我的函數(shù)只有兩個(gè)參數(shù),這時(shí)可以用bind綁定一個(gè)參數(shù),即可適配
- 簡(jiǎn)化重復(fù)調(diào)用:若某函數(shù)頻繁用相同參數(shù)調(diào)用,可以用bind綁定,簡(jiǎn)化函數(shù)
3.實(shí)戰(zhàn)案例
3.1.逆波蘭表達(dá)式求值(function + map優(yōu)化版本)
function + map --> “操作符 - 函數(shù)”映射
代碼示例:
#include <stack>
#include <vector>
#include <string>
#include <functional>
#include <map>
using namespace std;
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> st;
// 用 map 存儲(chǔ)“操作符-function”映射
map<string, function<int(int, int)>> op_map = {
{"+", [](int a, int b) { return a + b; }},
{"-", [](int a, int b) { return a - b; }},
{"*", [](int a, int b) { return a * b; }},
{"-", [](int a, int b) { return a - b; }},
{"/", [](int a, int b) { return a / b; }},
{"%", [](int a, int b) { return a % b; }}
};
for (auto& str : tokens) {
if (op_map.count(str)) { // 匹配到操作符
int right = st.top(); st.pop();
int left = st.top(); st.pop();
// 調(diào)用對(duì)應(yīng)的 function
st.push(op_map[str](left, right));
}
else {
st.push(stoi(str));
}
}
return st.top();
}
};3.2.復(fù)利計(jì)算
在計(jì)算復(fù)利時(shí),需要傳入三個(gè)參數(shù):利率、本金、年限,如果我們想固定利率和年限,只輸入本金,則可用bind簡(jiǎn)化函數(shù)。
代碼示例:
#include <functional>
#include <iostream>
using namespace std;
using namespace placeholders;
int main() {
// 復(fù)利計(jì)算 lambda:rate=年利率,money=本金,year=年限,返回利息
auto calc_interest = [](double rate, double money, int year) -> double {
double ret = money;
for (int i = 0; i < year; i++) {
ret += ret * rate; // 每年復(fù)利
}
return ret - money; // 利息 = 最終金額 - 本金
};
// 用 bind 固定利率和年限,生成專(zhuān)用函數(shù)(只需傳入本金)
function<double(double)> interest_3y_1_5 = bind(calc_interest, 0.015, _1, 3); // 3年1.5%利率
function<double(double)> interest_5y_2_0 = bind(calc_interest, 0.020, _1, 5); // 5年2.0%利率
function<double(double)> interest_10y_2_5 = bind(calc_interest, 0.025, _1, 10); // 10年2.5%利率
// 調(diào)用簡(jiǎn)化版函數(shù)
cout << "100萬(wàn) 3年1.5%利息:" << interest_3y_1_5(1000000) << endl; // 約45678.38
cout << "100萬(wàn) 5年2.0%利息:" << interest_5y_2_0(1000000) << endl; // 約104080.80
cout << "100萬(wàn) 10年2.5%利息:" << interest_10y_2_5(1000000) << endl; // 約280084.50
return 0;
}運(yùn)行結(jié)果:

4.注意事項(xiàng)
- function非靜態(tài)成員函數(shù)時(shí),由于非靜態(tài)成員函數(shù)參數(shù)中隱藏了this指針,因此function參數(shù)列表必須包含
this指針對(duì)應(yīng)的對(duì)象類(lèi)型(指針或引用),否則編譯報(bào)錯(cuò)。 - bind占位符在命名空間
std::placeholders中,使用前記得顯式聲明using namespace std::placeholders。 - 若用bind綁定引用參數(shù),需用
ref()或cref()包裝,否則bind會(huì)默認(rèn)按值傳遞。
void print(int& x) { x++; cout << x << endl; }
int main() {
int a = 10;
auto func = bind(print, ref(a)); // 用 ref 綁定引用
func(); // 輸出 11,a 被修改為 11
return 0;
}- 包裝器底層是函數(shù)對(duì)象封裝,無(wú)額外性能消耗,不必?fù)?dān)心效率問(wèn)題。
結(jié)語(yǔ)
std::function 和 std::bind 作為 C++11 引入的強(qiáng)大工具,共同為處理復(fù)雜的函數(shù)調(diào)用場(chǎng)景帶來(lái)了革命性的簡(jiǎn)化:它們消除了不同可調(diào)用對(duì)象(如普通函數(shù)、Lambda 表達(dá)式、成員函數(shù))之間的類(lèi)型壁壘,使得函數(shù)的傳遞、存儲(chǔ)和調(diào)用變得前所未有的統(tǒng)一和靈活。開(kāi)發(fā)者無(wú)需再為每種回調(diào)類(lèi)型定義繁瑣的函數(shù)指針或適配器,std::function 提供了一個(gè)通用的 “容器”,而 std::bind 則像一個(gè)萬(wàn)能的 “適配器”,能夠輕松調(diào)整函數(shù)簽名,固定參數(shù)或重排參數(shù)順序,極大地提升了代碼的表達(dá)力和可維護(hù)性。
到此這篇關(guān)于C++11中的包裝器的文章就介紹到這了,更多相關(guān)C++ 包裝器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++控制臺(tái)循環(huán)鏈表實(shí)現(xiàn)貪吃蛇
這篇文章主要為大家詳細(xì)介紹了C++控制臺(tái)循環(huán)鏈表實(shí)現(xiàn)貪吃蛇,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04
C語(yǔ)言實(shí)現(xiàn)掃雷算法簡(jiǎn)易版
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)掃雷算法簡(jiǎn)易版,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07
C++全面細(xì)致講解復(fù)數(shù)類(lèi)
本文章向大家介紹C++ 標(biāo)準(zhǔn)庫(kù)中的復(fù)數(shù)類(lèi),主要包括C++ 標(biāo)準(zhǔn)庫(kù)中的復(fù)數(shù)類(lèi)使用實(shí)例、應(yīng)用技巧、基本知識(shí)點(diǎn)總結(jié)和需要注意事項(xiàng),具有一定的參考價(jià)值,需要的朋友可以參考一下2022-06-06
介紹C語(yǔ)言中tolower函數(shù)的實(shí)例
這篇文章主要介紹了介紹C語(yǔ)言中tolower函數(shù)的實(shí)例,本文列出了該函數(shù)的頭文件,功能說(shuō)明等,以及如何使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07
C++中左值引用,右值引用,萬(wàn)能引用的關(guān)系及區(qū)別說(shuō)明
這篇文章主要介紹了C++中左值引用,右值引用,萬(wàn)能引用的關(guān)系及區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-03-03
C語(yǔ)言 OpenCV實(shí)現(xiàn)柱面投影
在做全景拼接的時(shí)候,為了保持圖片中的空間約束與視覺(jué)的一致性,需要進(jìn)行柱面投影,否則離中心圖像距離越遠(yuǎn)的圖像拼接后變形越大。本文將具體介紹一下這如何實(shí)現(xiàn),需要的可以參考一下2021-12-12

