各位大佬好,我是落羽!一個堅持不斷學習進步的學生。
如果您覺得我的文章還不錯,歡迎多多互三分享交流,一起學習進步!
也歡迎關注我的blog主頁: 落羽的落羽
文章目錄
- 一、function
- 1. 概念
- 2. 用法
- 二、bind
- 1. 概念
- 2. 用法
一、function
1. 概念
上一篇文章我們學習了lambda表達式的用法。
std::function
是 C++11 標準庫在 <functional>
頭文件中引入的一個通用、多態的函數包裝器。它的本質是一個類模板,可以包裝、存儲、復制和調用任何可調用對象(函數指針、仿函數、lambda表達式、bind表達式等),存儲的可調用對象被稱為function的目標。function不含目標則為空,調用空function的目標會拋異常。
函數指針、仿函數、lambda表達式等可調用對象的類型各不相同,function可以統一類型,對他們進行包裝,這樣在很多地方就方便聲明可調用對象的類型。
2. 用法
以上是function的原型,使用語法為:
#include <functional>
std::function<返回類型(參數類型1, 參數類型2, ...)> 包裝器名稱;
來看一段代碼實例:
#include <iostream>
#include <functional>
using namespace std;// 普通函數
int add(int a, int b)
{return a + b;
}// Lambda表達式
auto multiply = [](int a, int b) { return a * b; };// 仿函數
struct Subtract
{int operator()(int a, int b) const {return a - b;}
};int main()
{// 聲明一個function,他可以包裝一個返回int,接受兩個int參數的可調用對象function<int(int, int)> func;// 包裝普通函數func = add;cout << "Add: " << func(10, 5) << endl; // 輸出 15// 包裝 Lambda 表達式func = multiply;cout << "Multiply: " << func(10, 5) << endl; // 輸出 50// 包裝仿函數對象Subtract sub;func = sub;cout << "Subtract: " << func(10, 5) << endl; // 輸出 5// 甚至可以包裝一個臨時的Lambdafunc = [](int a, int b) { return a / b; };cout << "Divide: " << func(10, 5) <<std::endl; // 輸出 2return 0;
}
有一個特殊的點是,類的成員函數也可以被包裝,但成員函數必須要指定類域并且前面加上&才能獲取地址,靜態成員函數可以不加&,但是為了方便記憶,建議成員函數都加上吧。這時還有一個問題,普通成員函數還有一個隱含的this指針,在類外包裝時,也一定要顯式寫出this指針參數類型,即當前類的指針類型:
class Plus
{
public:Plus(int n = 10):_n(n){}static int plusi(int a, int b){return a + b;}double plusd(double a, double b){return (a + b) * _n;}private:int _n;
};int main()
{function<int(int, int)> f = &Plus::plusi;cout << f(1, 1) << endl; // 輸出2function<double(Plus*, double, double)> f1 = &Plus::plusd;//調用時實例化出一個對象取地址傳參即可,或者傳對象也可以Plus pdcout << f1(&pd, 1.1, 1.1) << endl; // 輸出22/*function<double(Plus, double, double)> f1 = &Plus::plusd;Plus pdcout << f1(pd, 1.1, 1.1) << endl; */return 0;
}
二、bind
1. 概念
std::bind是一個函數模板,也包含在<functional>
中,是一個可調用對象的包裝器,可以把他看做一個函數適配器,對接收的可調用對象處理后返回一個可調用對象。bind可以用來調整參數個數和參數順序。
2. 用法
調用bind的一般形式為:auto newCallable = bind(callable, arg_list);
其中newCallable本身是一個可調用對象,arg_list是一個用逗號分隔的參數列表,對應給定callable的參數。arg_list中的參數可能包含形如_n的占位符,n是一個正整數,它們占據了傳遞給newCallable的參數的位置。n表示生成的可調用對象的參數的位置:如_1為newCallable的第1個參數,_2為newCallable的第2個參數,_3為newCallable的第3個參數,以此類推,_1/_2/_3…這些占位符都在一個叫placeholders
的命名空間中。
#include <functional>
using namespace placeholders;int Sub(int a, int b)
{return a - b;
}int main()
{// _1代表sub1的第一個參數,_2代表sub1的第二個參數。// bind內寫成_2, _1的順序,意味sub1的第二個參數會傳給Sub的第一個參數a,sub1的第一個參數會傳給Sub的第二個參數bauto sub1 = bind(Sub, _2, _1);cout << Sub(1, 2) << endl; cout << sub1(1, 2) << endl;return 0;
}
這是只改變參數順序的一般用法。
bind還有最常用的改變參數個數用法,這個用法一般是為了綁死某些參數,使之為一個固定值,使用時就不需要再傳參:
#include <functional>
using namespace placeholders;int Sub(int a, int b)
{return a - b;
}int main()
{// _1代表sub2的第一個參數,100代表綁死Sub的第一個參數a,a的值固定為100了// a的值固定了,傳參時就不需要傳給a,sub2的第一個參數就會傳給Sub的第二個參數bauto sub2 = bind(Sub, 100, _1);cout << Sub(1, 2) << endl;cout << sub2(1);return 0;
}
再比如,剛才上面講到function包裝類成員函數時說到,使用包裝后的對象時還需要傳給this指針一個參數。有了bind就可以提前綁死這個參數,后續每次使用就不需要額外傳了:
#include <functional>
using namespace placeholders;class Plus
{
public:Plus(int n = 10):_n(n){}double plusd(double a, double b){return (a + b) * _n;}
private:int _n;
};int main()
{function<double(double, double)> f = bind(&Plus::plusd, Plus(), _1, _2);cout << f(1, 2) << endl;return 0;
}
本篇完,感謝閱讀。