济南网络建站,wordpress抓取淘宝价格,网页设计个人网页制作,网上帮做一些小事赚零花钱的网站文章目录 std::function 包装器1. 使用方法2. 包装器的应用场景#xff1a;题目 - - 逆波兰表达式求值3. 成员函数 和 static 静态成员函数 使用 包装器 std::bind 适配器绑定1. 使用方法2. 调整参数 顺序3. 指定参数 / 参数个数的调整 std::function 包装器 std::function 包… 文章目录 std::function 包装器1. 使用方法2. 包装器的应用场景题目 - - 逆波兰表达式求值3. 成员函数 和 static 静态成员函数 使用 包装器 std::bind 适配器绑定1. 使用方法2. 调整参数 顺序3. 指定参数 / 参数个数的调整 std::function 包装器 std::function 包装器也叫做 适配器。 头文件如下 #includefunctional类模板原型如下 template class T function; // undefined template class Ret, class... Args
class functionRet(Args...); 作用是 对 可调用对象类型callable object 进行 再封装适配 C 中的 function 本质上是一个类模板。 首先我们如果针对相同的功能实现可以选用下面的方法但他们都有不同的类型
函数指针类型比较难写仿函数类中定义 operator()()lambda从底层角度来说其实也是仿函数
举例下面两个代码都实现了数据的相加使用方法是一样的但是他们的类型完全不同。
#includemap
#includefunctional // 包装器的头文件// 函数写法
int func(int a, int b)
{cout int f(int a, int b) endl;return a b;
}// 仿函数写法
struct Functor
{
public:int operator() (int a, int b){cout int operator() (int a, int b) endl;return a b;}
};即使他们的 返回值、参数列表 都相同。
如果有需求要这两个 函数 和 仿函数 声明出一个统一的类型即 使用 map 的数据结构把他们放入其中管理他们类型完全不同怎么写呢
// mapstring, xxx // 需要声明一个可调用的类型xxx 这个类型怎么写呢
// int(*pf1)(int,int) func; // 这样写就没法和别的统一一个类型无法和 map 规定的模板类型匹配用 包装器 就可以适配出可调用类型。 1. 使用方法
包装器定义格式function返回值(参数列表) func 可调用对象 可适配对象包括 函数指针 / 函数名、仿函数、lambda 即 function返回值(参数列表) 这个类型就可以标识一系列 相同返回值、参数列表 的可适配对象了。
具体用法如下图举例
直接定义使用
int main()
{functionint(int, int) f1 func;functionint(int, int) f2 Functor(); // 经过包装后这俩对象的类型就是一样的了functionint(int, int) f3 [](int a, int b) {cout [](int a, int b) {return a b;} endl;return a b;};cout f1(1, 2) endl; // int f(int a, int b)cout f2(10, 20) endl; // int operator() (int a, int b)cout f3(100, 200) endl; // [](int a, int b) {return a b;}return 0;
}做模板参数使用
int main()
{mapstring, functionint(int, int) opFuncMap;opFuncMap[函数指针] func;opFuncMap[仿函数] Functor();opFuncMap[lambda] [](int a, int b) {cout [](int a, int b) {return a b;} endl;return a b;};cout opFuncMap[lambda](1, 2) endl; // [](int a, int b) {return a b;}return 0;
}2. 包装器的应用场景题目 - - 逆波兰表达式求值 leetcode【150.逆波兰表达式求值】 给你一个字符串数组 tokens表示一个根据 逆波兰表示法 表示的算术表达式。 请你计算该表达式返回一个表示表达式值的整数。 注意 有效的算符为 ‘’、‘-’、‘*’ 和 ‘/’ 。每个操作数运算对象都可以是一个整数或者另一个表达式。两个整数之间的除法总是向零截断表达式中不含除零运算。输入是一个根据逆波兰表示法表示的算术表达式。答案及所有中间计算结果可以用 32 位 整数表示。 示例 输入tokens [“4”,“13”,“5”,“/”,“”] 输出6 解释该算式转化为常见的中缀算术表达式为(4 (13 / 5)) 6 #includestack
class Solution {
public:int evalRPN(vectorstring tokens) {stackint st;mapstring, functionint(int, int) opfuncMap {{,[](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; }}};for (auto str : tokens) // 遍历给出的 逆波兰表达式 字符串{// 看是否是算数操作符if (opfuncMap.count(str)) // 是操作符将 st 中最 top 的两个数据 pop 出来用 opfuncMap[str] 函数进行计算把结果 push 进 st{int right st.top();st.pop();int left st.top();st.pop();st.push(opfuncMap[str](left, right));}else // 不是操作符即是操作数push 到 st 中等待操作符出现后进行计算{st.push(stoi(str)); // string 转 int}}return st.top();}
};3. 成员函数 和 static 静态成员函数 使用 包装器
以这个类举例里面有一个静态成员函数 plusi一个非静态成员函数plusd
class Plus
{
public:Plus(int rate 2):_rate(rate) {}static int plusi(int a, int b) {return a b;}double plusd(double a, double b) {return (a b) * _rate;}private:int _rate 2;
};静态成员函数
函数名就可以代表函数指针不需要取地址。
非静态成员函数
需要写成 函数名因为非静态成员函数还有一个隐藏的参数 this*所以定义时还需要多声明一个参数即非静态成员函数所属类的类型名调用的时候也需要多传一个 所属类的 对象\匿名对象
int main()
{// 静态成员函数函数名就行functionint(int, int) f1 Plus::plusi;// 非静态成员函数函数名另 多一个参数functiondouble(Plus, double, double) f2 Plus::plusd; // 这里其实是Plus是类型是通过我们创建的对象调用的 plusd // 调用cout f1(1, 2) endl;cout f2(Plus(), 20, 20) endl; // 非静态多传一个匿名对象cout f2(Plus(3), 20, 20) endl; // 还可以给匿名对象一个构造值Plus pl(3); // 给有名对象当然也okcout f2(pl, 20, 20) endl;return 0;
}// 包装器的本质也是仿函数至于包装器定义非静态函数成员传模板参数时多传一个类类型作为参数为了填补 this*为啥不直接写成指针的格式
因为如果这里声明成指针我们使用的时候就不能用匿名对象因为匿名对象是右值不能取地址这样调用了所以把这类型包装器第一个参数设计成指针的写法不方便。
// 不推荐这样写 ~~~
functiondouble(Plus*, double, double) f3 Plus::plusd;
Plus plus();
cout f3(plus, 5, 3) endl;std::bind 适配器绑定 std::bind 函数定义在头文件中是一个函数模板原型如下 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); 它就像一个函数包装器接受一个可调用对象生成一个新的可调用对 象来 适应和调整 原对象的 参数列表个数、顺序 一般而言我们用它可以把一个原本接收 N 个参数的函数 fn通过绑定一些参数返回一个接收 M 个参数的新函数M 可以大于 N但这么做没什么意义。同时使用 std::bind 函数还可以实现参数顺序调整等操作。 1. 使用方法
调用 bind 的一般形式
auto newCallable bind(callable, arg_list);newCallable 本身是一个可调用对象arg_list 是一个逗号分隔的参数列表对应给定的 callable 的参数。
当我们调用 newCallable 时newCallable 会调用 callable并传给它 arg_list 中的参数。
占位符
arg_list 中的参数可能包含形如 xxx_n 的名字其中 n 是一个整数这些参数就是 占位符表示 newCallable 的参数它们占据了传递给 newCallable 的参数的 “位置”。
数值 n 表示生成的可调用对象中参数的位置_1 为 newCallable 的第一个参数_2 为第二个参数以此类推。 综上我们能知道 bind 实现的是对绑定函数参数的调整。
当 bind() 中 arg_list 使用占位符的时候占位符 可以调整原函数 参数顺序当 arg_list 中传入具体参数的时候就相当于原函数该参数位置被 指定也就相当于在调用调整后的函数时可以少传参数了也就是对参数个数的调整。 2. 调整参数 顺序
使用占位符用来进行顺序的调整
举例使用如下
void print(int a, int b)
{cout a endl;cout b endl;
}
int main()
{print(10, 20);// _1 表示第一个参数_2 是第二个functionvoid(int,int) Rprint bind(print, placeholders::_2, placeholders::_1); //auto Rprint bind(print, placeholders::_2, placeholders::_1); Rprint(10, 20); // 20 10return 0;
}还是之前 给逆波兰表达式求值的代码在用法上面扩展一下只为使用语法
int plus(int a, int b)
{return a b;
}class Sub{
public:Sub(int rate 3):_rate(rate) {}int func(int a, int b) {return (a - b)*_rate;} // 这里 func 加 this* 有三个参数int operator()(int x, int y) {return x * y;}
private:int _rate;
};int mul(int x, int y)
{return x * y;
}class Solution {
public:int evalRPN(vectorstring tokens) {stackint st;mapstring, functionint(int, int) opfuncMap {{,[](int x, int y) {return x y; }}, // lambda 表达式{-,Sub()}, // 可以接收仿函数{*,mul}, // 可以接受函数指针{/,[](int x, int y) {return x / y; }},{,bind(Sub::func,Sub(3),placeholders::_1,placeholders::_2)}}; // 别的参数都是两个最后一个恰好是三个并且有一个能绑死就刚好用在这里// 代码略// 遍历给出的 逆波兰表达式 字符串// 看是否是算数操作符// 是操作符将 st 中最 top 的两个数据 pop 出来用 opfuncMap[str] 函数进行计算把结果 push 进 st// 不是操作符即是操作数push 到 st 中等待操作符出现后进行计算// return st.top();}
};
3. 指定参数 / 参数个数的调整
auto newCallable bind(callable, arg_list);arg_list 部分传入具体的参数就代表该位置被 指定 了调用调整后的函数就可以少传部分参数了。
举例使用如下
/*
class Sub{
public:Sub(int rate 3):_rate(rate) {}int func(int a, int b) {return (a - b)*_rate;} // 这里 func 加 this* 有三个参数int operator()(int x, int y) {return x * y;}
private:int _rate;
};
*/int main()
{// 不调整参数时functionint(Sub, int, int) fsub Sub::func; // 要加上取地址符cout fsub(Sub(1), 10, 20) endl;// bind 第一个参数functionint(int, int) fsub2 bind(Sub::func, Sub(3), placeholders::_1, placeholders::_2); cout fsub2(10, 20) endl;// bind 第二个参数注意functionint(Sub, int) fsub3 bind(Sub::func, placeholders::_1, 100, placeholders::_2); cout fsub3(Sub(2), 20) endl;return 0;
}如果本文对你有些帮助请给个赞或收藏你的支持是对作者大大莫大的鼓励(✿◡‿◡) 欢迎评论留言~~