【C++11】—— 包装器

  • 阿里云国际版折扣https://www.yundadi.com

  • 阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

    目录

    一、function包装器

    1. function包装器基本介绍

    2. function包装器统一类型

    3. function包装器的使用场景 

    二、bind包装器 


    一、function包装器

    1. function包装器基本介绍

    function包装器 也叫作适配器。C++中的function本质是一个类模板也是一个包装器。

    function的作用是将具有相同调用形式的不同类型的可调用对象进行类型统一。

    //function类模板的原型如下
    template <class T> function;    
    template <class Ret, class... Args>
    class function<Ret(Args...)>;
    

    模板参数说明

    • Ret被包装的可调用对象的返回值类型。
    • Args... 被包装的可调用对象的形参类型。

    2. function包装器统一类型

            如下图代码所示我们有一个函数模板分别以三种不同的形式进行调用那么这个函数模板就会实例化出三份useF函数

    template<class F, class T>
    T useF(F f, T x)
    {
    	static int count = 0;
    	cout << "count:" << ++count << endl;
    	cout << "count:" << &count << endl;
    	return f(x);
    }
    
    double f(double i)
    {
    	return i / 2;
    }
    
    struct Functor
    {
    	double operator()(double d)
    	{
    		return d / 3;
    	}
    };
    
    int main()
    {
    	// 函数名
    	cout << useF(f, 11.11) << endl;
    
    	// 函数对象
    	cout << useF(Functor(), 11.11) << endl;
    
    	// lamber表达式
    	cout << useF([](double d)->double { return d / 4; }, 11.11) << endl;
    
    	return 0;
    }

    从下面的运行结果就可以看到count的地址是不一样的因为实例化出了三份useF函数
            useF可能是什么呢那么useF可能是函数名函数指针函数对象(仿函数对象)也有可能是lamber表达式对象

            所以这些都是可调用的类型如此丰富的类型可能会导致模板的效率低下 

    但是C++11有了包装器以后就发了很大的变化

    template<class F, class T>
    T useF(F f, T x)
    {
    	static int count = 0;
    	cout << "count:" << ++count << endl;
    	cout << "count:" << &count << endl;
    	return f(x);
    }
    
    int f(int a, int b)
    {
    	return a + b;
    }
    
    struct Functor
    {
    	int operator()(int a, int b)
    	{
    		return a * b;
    	}
    
    };
    
    class Plus {
    public:
    	static int plusi(int a, int b) {
    		return a + b + 1;
    	}
    	double plusd(double a, double b) {
    		return a + b;
    	}
    };
    int main()
    {
    	//包装函数指针
    	function<int(int, int)> f1 = f;
    	cout << "f: " <<  f1(1, 2) << endl;
    
    	//包装仿函数
    	function<int(int, int)> f2 = Functor();
    	cout << "Functor(): " << f2(1, 2) << endl;
    
    	//包装静态的成员函数
    	function<int(int, int)> f3 = Plus::plusi; 
    	cout << f3(1, 2) << endl;
    
    	//包装非静态的成员函数---需要在调用的时候多加一个参数
    	function<double(Plus, double, double)> f4 = Plus::plusd;
    	cout << f4(Plus(), 1.1, 2.2) << endl;
    
    	//包装lamber表达式
    	function<int(int, int)> f5 = [](int a, int b)->double { return a * b; };
    	cout << f5(1, 5) << endl;
    
    	return 0;
    }

    3. function包装器的使用场景 

     逆波兰表达式

    class Solution {
    public:
        int evalRPN(vector<string>& tokens) {
            map<string, function<int(int, int)>> opFuncMap;
            opFuncMap["+"] = [](int a, int b)->int{return a + b;};
            opFuncMap["-"] = [](int a, int b)->int{return a - b;};
            opFuncMap["*"] = [](int a, int b)->int{return a * b;};
            opFuncMap["/"] = [](int a, int b)->int{return a / b;};
            stack<int> s;
            for(size_t i = 0; i < tokens.size(); ++i)
            {
                string& str = tokens[i];
                //str是操作数
                if(opFuncMap.find(str) == opFuncMap.end())
                {
                    s.push(stoi(str));
                    //s.push(atoi(str.c_str()));
                }
                else
                {
                    //str是操作符
                    int right = s.top();
                    s.pop();
                    int left = s.top();
                    s.pop();
                    s.push(opFuncMap[str](left, right));
                }
            }
            return s.top();
        }
    };

    二、bind包装器 

    std::bind函数定义在头文件中是一个函数模板它就像一个函数包装器(适配器)接受一个可调用对象callable object生成一个新的可调用对象来“适应”原对象的参数列表。一般而言我们用它可以把一个原本接收N个参数的函数fn通过绑定一些参数返回一个接收M个M可以大于N但这么做没什么意义参数的新函数。同时使用std::bind函数还可以实现参数顺序调整等操作。

    template <class Fn, class... Args>
    /* unspecified */ bind(Fn&& fn, Args&&... args);
    template <class Ret, class Fn, class... Args>
    /* unspecified */ bind(Fn&& fn, Args&&... args);
    

    模板参数说明

    • fn可调用对象。
    • args...要绑定的参数列表值或占位符。
            可以将bind函数看作是一个通用的函数适配器它接受一个可调用对象生成一个新的可调用对象来“适应”原对象的参数列表。
    调用bind的一般形式
    auto newCallable = bind(callable,arg_list);

            其中newCallable本身是一个可调用对象arg_list是一个逗号分隔的参数列表对应给定的callable的参数。当我们调用newCallable时newCallable会调用callable,并传给它arg_list中的参数。

            arg_list中的参数可能包含形如_n的名字其中n是一个整数这些参数是“占位符”表示newCallable的参数它们占据了传递给newCallable的参数的“位置”。数值n表示生成的可调用对象中参数的位置_1为newCallable的第一个参数_2为第二个参数以此类推。
    // 使用举例
    #include <functional>
    int Plus(int a, int b)
    {
        return a + b;
    }
    
    class Sub
    {
    public:
        int sub(int a, int b)
        {
            return a - b;
        }
    };
    
    int main()
    {
        //表示绑定函数plus 参数分别由调用 func1 的第一二个参数指定
        std::function<int(int, int)> func1 = std::bind(Plus,placeholders::_1,
    placeholders::_2);
    
        //auto func1 = std::bind(Plus, placeholders::_1, placeholders::_2);//使用auto
    
        //func2的类型为 function<void(int, int, int)> 与func1类型一样
        //表示绑定函数 plus 的第一二为 1 2
        auto  func2 = std::bind(Plus, 1, 2);   
        cout << func1(1, 2) << endl;
        cout << func2() << endl;
    
        Sub s;
        // 绑定成员函数
        std::function<int(int, int)> func3 = std::bind(&Sub::sub, s, 
    placeholders::_1, placeholders::_2);
    
        // 参数调换顺序
        std::function<int(int, int)> func4 = std::bind(&Sub::sub, s, 
    placeholders::_2, placeholders::_1);
    
        cout << func3(1, 2) << endl; 
        cout << func4(1, 2) << endl;
    
        return 0;
    }

    bind包装器的意义

    • 将一个函数的某些参数绑定为固定的值让我们在调用时可以不用传递某些参数。
    • 可以对函数参数的顺序进行灵活调整。
  • 阿里云国际版折扣https://www.yundadi.com

  • 阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
    标签: c++