文章目录
- 包装器:function
- 包装器:bind
包装器:function
-
function接口介绍
在头文件
<functional>
中
-
语法:function的语法比较特殊
function<返回值(参数)> 自定义变量名 = 要被包装的可调用对象-
class Plus { public:static int plusi(int a, int b){return a + b;}double plusd(double a, double b){return a + b;} };
-
包装静态成员函数:对调用的函数指定类域即可
int main() {// 类的静态成员函数std::function<int(int, int)> func4 = &Plus::plusi;cout << func4(1, 2) << endl; }
-
包装非静态成员函数:要对调用的函数指定类域,且在类域前加上取地址符号。且非静态成员函数包含了一个隐藏的this指针。因此参数类型还要加上this指针,加上该类类型的指针/该类类型本身
int main() {// 类的非静态成员函数std::function<double(Plus*, double, double)> func5 = &Plus::plusd;std::function<double(Plus, double, double)> func6 = &Plus::plusd; }
- 为什么非静态成员中是有一个隐藏的this指针,但是加上的参数类型可以为该类类型的指针也可以为该类的类类型呢?
这是因为在底层上 包装器 实际上是通过operator()中的一系列操作后找到 该非静态成员函数 然后调用该非静态成员类型函数。而要找到该非静态成员函数 就需要 该类类型的指针/该类类型。
- 为什么非静态成员中是有一个隐藏的this指针,但是加上的参数类型可以为该类类型的指针也可以为该类的类类型呢?
-
-
function的作用
包装任意的可调用对象 -
目前学到的对象:函数指针;仿函数;lambda表达式
-
样例
#include <functional> int f(int a, int b) {return a + b; } struct Functor { public:int operator() (int a, int b){return a + b;} }; class Plus { public:static int plusi(int a, int b){return a + b;}double plusd(double a, double b){return a + b;} };int main() {// 函数名(函数指针)std::function<int(int, int)> func1 = f;cout << func1(1, 2) << endl;// 函数对象std::function<int(int, int)> func2 = Functor();cout << func2(1, 2) << endl;// lamber表达式std::function<int(int, int)> func3 = [](const int a, const int b) {return a + b; };cout << func3(1, 2) << endl;// 类的成员函数std::function<int(int, int)> func4 = &Plus::plusi;cout << func4(1, 2) << endl;std::function<double(Plus, double, double)> func5 = &Plus::plusd;cout << func5(Plus(), 1.1, 2.2) << endl;return 0; }
其他应用场景之一:150. 逆波兰表达式求值 - 力扣(LeetCode)
题解class Solution { public:int evalRPN(vector<string>& tokens) {stack<int> st;map<string,function<int(int,int)>> opFunc={{"+",[](int x, int y){return x + y;}},{"-",[](int x, int y){return x - y;}},{"*",[](int x, int y){return x * y;}},{"/",[](int x, int y){return x / y;}},};int ret = stoi(tokens[0]);for(auto& e : tokens){if(opFunc.count(e)){int right = st.top();st.pop();int left = st.top();st.pop();ret = opFunc[e](left,right);st.push(ret);}else{st.push(stoi(e));}}return ret;} };
包装器:bind
bind也称为 “绑定”,可以改变函数参数的顺序
std::bind函数定义在头文件中,是一个函数模板,它就像一个函数包装器(适配器),接受一个可 调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表。
一般而 言,我们用它可以把一个原本接收N个参数的函数fn,通过绑定一些参数,返回一个接收M个(M 可以大于N,但这么做没什么意义)参数的新函数。
同时,使用std::bind函数还可以实现参数顺 序调整等操作。
-
bind接口介绍
-
第一个参数是可调用对象
-
第二个参数是 placeholders 命名空间的标识符
该命名空间的第一个标识符_1表示函数的第一个参数,_2表示函数的第二个参数,_3代表函数的第三个参数,依次类推
-
-
语法
bind的返回值也只能通过auto来推导 -
样例
-
using placeholders::_1; using placeholders::_2; using placeholders::_3;int Sub(int a, int b) {return (a - b) * 10; }int SubX(int a, int b, int c) {return (a - b - c) * 10; }
-
基本语法
auto sub = bind(Sub,_1,_2);cout << sub(10,5) << endl;
-
调整参数顺序
// bind 本质返回的一个仿函数对象// 调整参数顺序(不常用)// _1代表第一个实参// _2代表第二个实参// ...auto sub2 = bind(Sub, _2, _1);cout << sub2(10, 5) << endl;
-
调整参数个数
// 调整参数个数 (常用)auto sub3 = bind(Sub, 100, _1);cout << sub3(5) << endl;auto sub4 = bind(Sub, _1, 100);cout << sub4(5) << endl;// 分别绑死第1,2,3个参数auto sub5 = bind(SubX, 100, _1, _2);cout << sub5(5, 1) << endl;auto sub6 = bind(SubX, _1, 100, _2);cout << sub6(5, 1) << endl;auto sub7 = bind(SubX, _1, _2, 100);cout << sub7(5, 1) << endl;
-
-
绑定bind一般用于,一般固定绑死的参数。例如:function调用非静态成员函数时的类类型的指针/类类型。 绑死利率等等也是应用场景
// bind一般用于,绑死一些固定参数function<double(double, double)> f7 = bind(&Plus::plusd, Plus(), _1, _2);cout << f7(1.1, 1.1) << endl;//auto func1 = [](double rate, double monty, int year)->double {return monty * rate * year;};auto func1 = [](double rate, double monty, int year)->double {double ret = monty;for (int i = 0; i < year; i++){ret += ret * rate;}return ret - monty;};//绑死利率//3年期0.015利率function<double(double)> func3_1_5 = bind(func1, 0.015, _1, 3);//5年期0.015利率function<double(double)> func5_1_5 = bind(func1, 0.015, _1, 5);//10年期0.025利率function<double(double)> func10_2_5 = bind(func1, 0.025, _1, 10);//10年期0.035利率function<double(double)> func20_3_5 = bind(func1, 0.035, _1, 30);//输入 存储的钱 , 输出 利息产生的钱cout << func3_1_5(1000000) << endl;cout << func5_1_5(1000000) << endl;cout << func10_2_5(1000000) << endl;cout << func20_3_5(1000000) << endl;