• 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Lambda表达式

    int main()
    {	
    	double m=10.1;
    	function<double(double)> f2 = [](double i){return i/2;};//Lambda表达式
    	cout<<f2(m)<<endl;
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    函数指针

    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<
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    类成员函数

    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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    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();
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    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进行接收
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
  • 相关阅读:
    vue的学习笔记(1):v-on的使用
    【Spring Cloud】网关Gateway的请求过滤工厂RequestRateLimiterGatewayFilterFactory
    ES千亿级数据检索实战-搜索优化建议
    机器学习理论基础—支持向量机的推导(一)
    springboot毕设项目宠物咖啡馆系统的设计与实现ok8a3(java+VUE+Mybatis+Maven+Mysql)
    FEDformer 代码分析(1)
    继承的详解
    糟糕,CPU100%了!!!
    Unity中URP实现水体(水下的扭曲)
    谷粒学院16万字笔记+1600张配图(四)——前端技术
  • 原文地址:https://blog.csdn.net/m0_61567378/article/details/126457494