当前位置: 首页 > news >正文

h5页面制作免费平台网站seo百度百科

h5页面制作免费平台,网站seo百度百科,logo设计网站在线,中卫网站设计公司排名文章目录 std::function 包装器1. 使用方法2. 包装器的应用场景:题目 - - 逆波兰表达式求值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 包装器,也叫做 适配器。
头文件如下:

#include<functional>

类模板原型如下:

template <class T> function;     // undefined template <class Ret, class... Args> 
class function<Ret(Args...)>; 

作用是 对 可调用对象类型(callable object) 进行 再封装适配
C++ 中的 function 本质上是一个类模板

首先我们如果针对相同的功能实现,可以选用下面的方法,但他们都有不同的类型:

  • 函数指针:类型比较难写
  • 仿函数(类中定义 operator()())
  • lambda:从底层角度来说其实也是仿函数

举例下面两个代码,都实现了数据的相加,使用方法是一样的,但是他们的类型完全不同。

#include<map>
#include<functional>	// 包装器的头文件// 函数写法
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 的数据结构,把他们放入其中管理,他们类型完全不同,怎么写呢?

// map<string, xxx>			// 需要声明一个可调用的类型,xxx 这个类型怎么写呢
// int(*pf1)(int,int) = func;	// 这样写就没法和别的统一一个类型,无法和 map 规定的模板类型匹配

用 包装器 就可以适配出可调用类型。


1. 使用方法

包装器定义格式:function<返回值(参数列表)> func = 可调用对象

  • 可适配对象包括:
    函数指针 / 函数名、仿函数、lambda

  • function<返回值(参数列表)> 这个类型,就可以标识一系列 相同返回值、参数列表 的可适配对象了。

🌰具体用法如下图举例:

  1. 直接定义使用:
int main()
{function<int(int, int)> f1 = func;function<int(int, int)> f2 = Functor();		// 经过包装后这俩对象的类型就是一样的了function<int(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;
}
  1. 做模板参数使用
int main()
{map<string, function<int(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
#include<stack>
class Solution {
public:int evalRPN(vector<string>& tokens) {stack<int> st;map<string, function<int(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()
{// 静态成员函数,函数名就行function<int(int, int)> f1 = Plus::plusi;// 非静态成员函数,&函数名,另 多一个参数function<double(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*,为啥不直接写成指针的格式?

因为,如果这里声明成指针,我们使用的时候就不能用匿名对象(因为匿名对象是右值不能取地址)这样调用了,所以把这类型包装器第一个参数设计成指针的写法不方便。

// 不推荐这样写 ~~~
function<double(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 是第二个function<void(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(vector<string>& tokens) {stack<int> st;map<string, function<int(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()
{// 不调整参数时function<int(Sub, int, int)> fsub = &Sub::func;	// 要加上取地址符cout << fsub(Sub(1), 10, 20) << endl;// bind 第一个参数function<int(int, int)> fsub2 = bind(&Sub::func, Sub(3), placeholders::_1, placeholders::_2);	cout << fsub2(10, 20) << endl;// bind 第二个参数:注意function<int(Sub, int)> fsub3 = bind(&Sub::func, placeholders::_1, 100, placeholders::_2);	cout << fsub3(Sub(2), 20) << endl;return 0;
}

🥰如果本文对你有些帮助,请给个赞或收藏,你的支持是对作者大大莫大的鼓励!!(✿◡‿◡) 欢迎评论留言~~


http://www.ds6.com.cn/news/58592.html

相关文章:

  • 东莞阳光网新闻百度seo关键词优化公司
  • 海口网站建设高端cms建站系统
  • 做网站用什么域名比较好济南百度推广开户
  • 网站安全防护方案手机百度浏览器
  • 企业微信网站怎么做杭州seo网络推广
  • 乌鲁木齐做四维彩超哪凤凰L网站厦门网站优化公司
  • 建设局网站自查自纠高级搜索百度
  • 展示用网站模板网络推广员的工作内容
  • 可信网站代码韶关今日头条新闻
  • 南京网页设计招聘qq排名优化网站
  • 国内平台有哪些优化大师破解版app
  • 深圳做网站设计制作开发广东seo网络培训
  • 做的网站怎么让别人也能看到吗成都网站推广哪家专业
  • 网站关键词优化wang西安关键词排名软件
  • 做二手的网站都有哪些互联网网络推广公司
  • 做百度网站排名软件防疫优化措施
  • 重庆模板网站建设百度指数的数值代表什么
  • 网站非法字符过滤阿里巴巴国际站官网
  • 郴州58网站优化推广网站怎么做
  • 备案时如何关闭网站凡科建站怎么收费
  • 备案网站域名被抢注seo优化步骤
  • 公司法人查询优化网站排名推广
  • asp装饰公司网站源码新手怎么入行seo
  • 一台vps可以做几个网站网页开发培训网
  • 电子工程网官网杭州谷歌seo公司
  • 兰州做网站的有哪几个中国建设网官方网站
  • 湛江市企业网站建设哪家好百度公司名称
  • 口碑营销的定义优化营商环境的金句
  • 谈谈什么是网络营销seo优化知识
  • 织梦网站模板使用教程互联网销售公司