C++包装器

概述

包装器可以对一个可调用对象进行包装
可调用对象包括

  • lambda表达式
  • 仿函数
  • 函数指针

使用包装器可以避免模板实例化出多份代码,可以提高效率

function

function的使用

function可以使用构造函数进行初始化,也能用赋值进行初始化
function< ( …)>:function括号里面就是包装的函数的类型对应的参数类型,括号外面就是函数的返回值

仿函数

struct Functor
{
   double operator()(double i)
   {
       return i / 2;
   }
};
int main()
{	
	double m=10.1;
	function<double(double)> f2 = Functor(); //仿函数对象
	cout<<f2(m)<<endl;
	return 0;
}

Lambda表达式

int main()
{	
	double m=10.1;
	function<double(double)> f2 = [](double i){return i/2;};//Lambda表达式
	cout<<f2(m)<<endl;
	return 0;
}

函数指针

void l(int& x)
{
    x+=2;
    cout<<"222"<<endl;
}

void demo4()
{
    int x=2;
    function<void(int&)> s=l;
    s(x);
    cout<<x<<endl;
    // cout<<ret<<endl;
}

类成员函数

class Plus
{
public:
   static double fI(double x)
   {
       return x;
   }
   double f(double i)
   {
       return i / 2;
   }
};

int main()
{
	//只要是成员函数就要加&
   function<double(double)> f3 = &Plus::fI; //静态的成员函数
   //还可以包装成员函数
   cout << f2(10) << endl;
   //对于非静态的成员函数
   function<double(Plus, double)> ff = &Plus::f; //非静态的成员函数要多加一个Plus,因为有this指针
   cout << ff(Plus(), 123) << endl;//使用的时候要多添加一个类对象(可以是匿名对象)
	return 0;
}

function的实战

逆波兰表达式

根据 逆波兰表示法,求表达式的值。
有效的算符包括 +、-、、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
注意 两个整数之间的除法只保留整数部分。
可以保证给定的逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例 1:
输入:tokens = [“2”,“1”,“+”,“3”,"
“]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
示例 2:
输入:tokens = [“4”,“13”,“5”,”/“,”+“]
输出:6
解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
示例 3:
输入:tokens = [“10”,“6”,“9”,“3”,”+“,”-11",““,”/“,””,“17”,“+”,“5”,“+”]
输出:22
解释:该算式转化为常见的中缀算术表达式为:
((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22

题解:如果是操作数就入栈,如果是操作符,就把栈顶的两个数取出来进行处理

我们可以使用map,命令和函数可以进行映射,映射到的为function,因为function对于函数指针,lambda表达式,仿函数都可以包装,所以就可以了,一个命令对应一个函数

class Solution
{
public:
    int evalRPN(vector<string> &tokens)
    {
        //使用列表初始化
        //包装器,只要是可调用对象就行了,很方便
        //使用包装器之后就能用函数映射了

        map<string, function<int(int, int)>> opMapFunc; //动作和函数映射的map

        //命令增加了只需要加这个map这里,一个命令对应一个函数

        opMapFunc["+"] = [](int a, int b)
        { return a + b; }; //包装器,初始化用函数指针,仿函数,lambda表达式
        opMapFunc["-"] = [](int a, int b)
        { return a - b; }; //包装器,初始化用函数指针,仿函数,lambda表达式
        opMapFunc["*"] = [](int a, int b)
        { return a * b; }; //包装器,初始化用函数指针,仿函数,lambda表达式
        opMapFunc["/"] = [](int a, int b)
        { return a / b; }; //包装器,初始化用函数指针,仿函数,lambda表达式

        //也可以用列表初始化

        stack<int> s;
        int i = 0;
        int top;
        //逆波兰表达式,一个命令和一个函数的映射关系就可以用包装器来解决

        for (int i = 0; i < tokens.size(); i++)
        {
            string &str = tokens[i]; //用别名弄,减少了拷贝
            // str为操作数
            // map里面为操作数就找不到
            if (opMapFunc.find(str) == opMapFunc.end())
            {
                //说明就是操作数
                s.push(stoi(str)); //入栈
            }
            else
            {
                //这里就是操作符
                int left = s.top();
                s.pop();
                int right = s.top();
                s.pop();
                //取出来了数据
                s.push(opMapFunc[str](left, right));
            }
        }
        return s.top();
    }
};

bind

  1. bind可以对function绑定的函数调整参数的顺序
  2. bind可以调整参数的个数(比如将包装之后的函数固定一个参数为某个东西,就不需要我们再手动去添加)

// bind也是一个函数包装器
//接收一个可调用对象,生成一个可调用对象
int sub(int a, int b)
{
    return a - b;
}

class subber
{
public:
    int Sub(int a, int b)
    {
        return a - b;
    }
};

void demo3()
{
    function<int(int, int)> f = sub;
    cout << f(10, 3) << endl;

    //调整参数的顺序
    function<int(int, int)> f1 = bind(sub,placeholders::_1,placeholders::_2);//这个就是啥都没做
    cout << f1(10, 3) << endl;
    function<int(int, int)> f3 = bind(sub,placeholders::_2,placeholders::_1);//参数顺序调换了
    //这里的_1就是把原来的第一个参数换到现在的位置,_2就是把原来的第2个参数换到现在的第一个

    //这个就是可以把库里面的用的不习惯的函数,切换参数顺序

    //主要是通过绑定来进行调整参数个数


    cout << f3(10, 3) << endl;
    function<int(subber,int, int)> f4 = &subber::Sub;
    cout << f4(subber(),10, 3) << endl;//使用了用还要加一个对象
    //每次都这样用很烦
    function<int(int, int)> f5 = bind(&subber::Sub,subber(),placeholders::_1,placeholders::_2);//这样子进行绑定,第一个参数就绑死了,使用的时候就不需要再去添加
    cout << f5(10, 3) << endl;

    //假如说第一个参数都是一样的
    function<int(int)> f6=bind(&subber::Sub,subber(),100,placeholders::_1);//第一个参数都是100
    cout<<f6(20)<<endl;
    //这里也能用auto进行接收

}
class A{


    public:
    A()=default;
void l(int &x)
{
    x += 2;
    cout << "222" << endl;
}
void ll(int &x)
{
    x += 2;
    cout << "222" << endl;
}
};

int main()
{
	map<int, function<void(int &)>> lll = {
        {X, bind(&A::ll,A(), placeholders::_1)},
        {2, bind(&A::l,A() ,placeholders::_1)}};
    lll[X](m);//映射包装器与bind,可以使得我们在用的时候,对类立案的参数就不要写了
	return 0;
}
  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zevin~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值