您的位置:首页 > 财经 > 产业 > 那个网站制作比较好_ai智能写作平台_昆明seo关键词排名_百度手机版

那个网站制作比较好_ai智能写作平台_昆明seo关键词排名_百度手机版

2024/12/21 20:32:06 来源:https://blog.csdn.net/2301_80277275/article/details/142369616  浏览:    关键词:那个网站制作比较好_ai智能写作平台_昆明seo关键词排名_百度手机版
那个网站制作比较好_ai智能写作平台_昆明seo关键词排名_百度手机版

目录

1、function包装器

2、function包装器包装成员函数指针

2.1 静态成员函数

2.2 非静态成员函数

3、bind包装器

3.1 调整参数顺序

3.2 调整参数个数


1、function包装器

包装器是用来包装可调用对象的,这里的可调用对象主要有函数指针、仿函数、lambda表达式

function本质是一个类模板,也是一个包装器,头文件是<functional>

function<返回值(参数列表)> f = 可调用对象

int f(int a, int b)
{return a + b;
}
struct Functor
{
public:int operator() (int a, int b){return a + b;}
};
int main()
{// 包装可调用对象function<int(int, int)> f1 = f;function<int(int, int)> f2 = Functor();function<int(int, int)> f3 = [](int a, int b) {return a + b; };cout << f1(1, 2) << endl;cout << f2(1, 2) << endl;cout << f3(1, 2) << endl;return 0;
}

优点是可以进行类型统一,就像我们玩游戏使用英雄释放技能时,按下一个技能的按键,英雄就会做出相应的动作,实际上,按下按键救会产生一个命令,命令通常是一个字符串,一般会将命令和函数进行映射。为了映射,此时可以使用一个map来完成映射,第一个参数存命令,第二个参数存这个命令对应的函数,但函数可能是函数指针、仿函数、lambda,lambda没有类型(底层有,但是同一个lambda在不同时间生成的类型都不一样),仿函数只能写死,函数指针可以,但太麻烦,所以就可以考虑使用包装器来进行统一

我们通过一个题目来看

150. 逆波兰表达式求值 - 力扣(LeetCode)

这道题普通的做法是开一个栈,遍历数组,当遍历到的字符是数字时,就放入栈,当遍历到的字符不是数字时,就取栈顶的两个数来进行操作,并将操作完成的数再放入栈

class Solution {
public:bool isNumber(const string& s){return !(s == "+" || s == "-" || s == "*" || s == "/");}int evalRPN(vector<string>& tokens) {stack<int> st;for(const auto& e : tokens){if(isNumber(e)) st.push(stoi(e));else{int y = st.top();// 注意:这里是用x / yst.pop();int x = st.top();st.pop();switch(e[0])// 这里不能是e{case '+':st.push(x + y);break;case '-':st.push(x - y);break;case '*':st.push(x * y);break;case '/':st.push(x / y);break;}}}return st.top();}
};

现在可以使用一个map,第一个参数存放操作符,第二个参数存放对应的操作

class Solution {
public:bool isNumber(const string& s){return !(s == "+" || s == "-" || s == "*" || s == "/");}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(const auto& e : tokens){if(isNumber(e)) st.push(stoi(e));else{int y = st.top();// 注意:这里是用x / yst.pop();int x = st.top();st.pop();int ret = opFuncMap[e](x, y);st.push(ret);}}return st.top();}
};

2、function包装器包装成员函数指针

2.1 静态成员函数

class Plus
{
public:static int plusi(int a, int b){return a + b;}double plusd(double a, double b){return a + b;}
};
int main()
{// 包装静态成员函数function<int(int, int)> f1 = Plus::plusi; // 要指定类域cout << f1(1, 1) << endl;return 0;
}

静态成员函数与普通函数是类似的,只是需要指定类域

2.2 非静态成员函数

int main()
{// 包装静态成员函数function<int(int, int)> f1 = Plus::plusi; // 要指定类域cout << f1(1, 1) << endl;// 包装非静态成员函数function<double(double, double)> f2 = Plus::plusd;return 0;
}

此时是错误的,非静态成员函数要取函数指针需要加&,静态成员函数可加可不加,最好也加上

int main()
{// 包装静态成员函数function<int(int, int)> f1 = &Plus::plusi; // 要指定类域cout << f1(1, 1) << endl;// 包装非静态成员函数function<double(double, double)> f2 = &Plus::plusd;return 0;
}

此时还是不行的,因为非静态成员函数还要隐藏的this指针,可以传指针,也可传对象(有名对象或匿名对象)

int main()
{// 包装静态成员函数function<int(int, int)> f1 = &Plus::plusi; // 要指定类域cout << f1(1, 1) << endl;// 包装非静态成员函数Plus ps;function<double(Plus*, double, double)> f2 = &Plus::plusd;cout << f2(&ps, 7.7, 7.7) << endl;// 包装非静态成员函数function<double(Plus, double, double)> f3 = &Plus::plusd;cout << f3(Plus(), 7.7, 7.7) << endl;return 0;
}

此时就会有一个疑问,非静态成员函数多出来的参数是this指针,是一个指针,为什么可以传对象呢?

实际上,function本质并不是将3个参数传给plusd,是拿到函数指针后,将函数指针作为成员变量存起来,我们传参时实际上是调用了function的operator(),operator()又去调用plusd,而调用plusd就需要用到Plus的对象或指针。也就是说,不是直接将3个参数传给plusd,并且this指针也不支持显示传参

3、bind包装器

bind是一个函数模板,主要用于对可调用对象调整参数的顺序、个数,返回一个仿函数,直接使用auto接收

placeholders是一个命名空间,里面有很多标识符(_1,_2,_3,...),可用这些标识符去代表对应的参数,_1始终代表第一个实参,_2代表第二个实参

3.1 调整参数顺序

using placeholders::_1;
using placeholders::_2;
using placeholders::_3;
int Sub(int x, int y)
{return (x - y) * 10;
}
int main()
{// 调整参数顺序auto sub1 = bind(Sub, _1, _2);cout << sub1(10, 5) << endl;auto sub2 = bind(Sub, _2, _1);cout << sub2(10, 5) << endl;return 0;
}

结果是50  -50。_1代表的始终是第1个实参,无论是sub1(10, 5),还是sub2(10, 5),第1个实参都是10,都会匹配到_1,但是sub1和sub2中_1处在的位置是不同的,sub1会将_1当成第1个形参来传,sub2会将_1当成是第2个形参来传,也就是说在调用函数时,是按顺序传的

3.2 调整参数个数

int main()
{// 调整参数顺序auto sub1 = bind(Sub, _1, _2);cout << sub1(10, 5) << endl;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;return 0;
}

结果是950  -950

实际上,bind返回的是一个仿函数对象,也就是说上面的sub1、sub2、sub3、sub4都是仿函数对象,本质也是调用operator(),只是里面调用的顺序不同

其实,bind主要用于绑定一些固定参数,向上面非静态成员函数的传参每次都需要传指针或对象,可用直接绑定了,这样只需要传操作数

class Plus
{
public:static int plusi(int a, int b){return a + b;}double plusd(double a, double b){return a + b;}
};
int main()
{function<double(double, double)> f1 = bind(&Plus::plusd, Plus(), _1, _2);cout << f1(7.7, 7.7) << endl;return 0;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com