欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 时评 > 【C++11】包装器:function与bind

【C++11】包装器:function与bind

2025/4/30 6:44:51 来源:https://blog.csdn.net/huangyuchi/article/details/147588088  浏览:    关键词:【C++11】包装器:function与bind

前言:

        上文我们学了C++11中一个新的表达式:Lambda表达式。Lambda表达式可以在函数内部定义,其本质是仿函数【C++11】Lambda表达式-CSDN博客

        本文我们来学习C++11的下一个新语法:包装器

function

function的定义为:

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

         function的一个类模板,也是一个包装器。function的实例对象可以包装调用一切可调用对象。但若function的对象为被初始化,进行调用就会报错(抛异常:std::bad_function_call)

        function模板类放在<functional>头文件中

        使用function包装不同的可调用对象,就可以用相同的方式调用不同可调用对象

        function的本质其实也是仿函数

  使用细节如下:

#include<iostream>
#include<functional>
using namespace std;
//function可以包装一切可调用对象,其本质是仿函数//template <class Ret, class... Args>
//class function<Ret(Args...)>;int f(int a, int b)
{return a + b;
}struct Functor
{int operator() (int a, int b){return a - b;}
};class Plus
{
public:Plus(int n = 10):_n(n){}static int plusi(int a, int b){return a + b;}double plusd(double a, double b){return (a + b) * _n;}private:int _n;
};int main()
{//可包装一切可调用对象function<int(int, int)> a = f;function<int(int, int)> b = Functor();function<int(int, int)> c = [](int a, int b) {return a * 10 + b; };cout << a(1, 2) << endl;cout << b(1, 2) << endl;cout << c(1, 2) << endl;//既然说function可以包装一切可调用对象,那么类成员函数既然也可以被包装//包装静态成员函数: 1.必须要指定类域,2.非静态成员必须要取地址,但是静态不用,为了同一格式建议加上function<int(int, int)> x = &Plus::plusi;cout << x(1, 2) << endl;//包装非静态成员函数:1.必须要指定类域 2.必须取地址 3.非静态成员函数有this指针function<int(Plus*,int, int)> y = &Plus::plusd;Plus p;cout << y(&p, 1, 2) << endl;//也可以直接传对象,因为:类成员函数的调用是通过 .* 运算符实现的//前面传指针,也是先将指针解引用为对象,再通过 .* 运算符调用成员函数function<int(Plus, int, int)> z = &Plus::plusd;cout << z(p, 1, 2) << endl;//与直接传对象类似,引用是为了减少拷贝,提高效率function<int(Plus&&, int, int)> q = &Plus::plusd;cout << q(move(p), 1, 2) << endl;function<int(Plus&, int, int)> w = &Plus::plusd;cout << w(p, 1, 2) << endl;
}

        包装其他可调用对象,没什么区别,唯独需要注意当我们在包装类成员函数时有一些不同:

        包装静态成员函数时:1.必须要指定类域,2.非静态成员必须要取地址,但是静态不用,为了统一格式建议加上。

        包装非静态成员函数时:1.必须要指定类域 2.必须取地址 3.非静态成员函数有this指针。

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

#include<iostream>
#include<vector>
#include<functional>
#include<map>
#include<stack>
#include<string>
using namespace std;class Solution
{
public:int evalRPN(vector<string>& tokens){stack<int> s;//使用map将运算符与运算逻辑匹配//使用Lambda实现运算逻辑//利用function包装Lambdamap<string, function<int(int, int)>> m ={{"+",[](int a,int b) {return a + b; }},{"-",[](int a,int b) {return a - b; }},{"*",[](int a,int b) {return a * b; }},{"/",[](int a,int b) {return a / b; }}};for (auto& e : tokens){//当count返回不是0,说明当前的字符是"+ - * /"中的一个//取两个操作数,进行相应的运算if (m.count(e)){int left = s.top();s.pop();int right = s.top();s.pop();//operator[]返回function对象的引用//function对象直接调用Lambda表达式int num = m[e](right, left);s.push(num);}else{s.push(stoi(e));//stoi函数:将字符串转化为整型}}return s.top();}
};int main()
{vector<string> arr = { "4","13","5","/","+" };cout << Solution().evalRPN(arr);
}

bind

bind的定义:

simple(1)
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);

        bind的一个模板函数,也是一个包装器,可以将其看作一个函数适配器。bind接收一个函数处理后会返回一个可调用对象。bind的功能:调整函数参数顺序、控制函数参数个数

        调用bind的一般形式为:auto newCallable = bind(callable,arg_list);callable是函数地址,newCallable是可调用对象,调用newCallable会将arg_list的参数传给callable,然后调用callable。bind的底层和function一样都是仿函数,所以也可以用function代替auto来接收bind的返回对象

        在arg_list中有一个特殊概念:占位符。假设有n个参数,那占位符至多有n个:_1 , _2 , _3 , ....... , _n。_1代表第一个参数,_2代表第二个参数,........ ,_n代表第n个参数。这些占位符放在placeholders命名空间

使用样例:

#include<iostream>
#include<functional>
using namespace std;
//bind的占位符都放在这个命名空间里
using namespace placeholders;//bind有两个作用:1.交换参数顺序 2.绑定参数,控制参数个数(常用)
//bind的本质和function一样都是仿函数class Plus
{
public:static int plusi(int a, int b){return a + b;}double plusd(double a, double b){return a + b;}
};int add(int a, int b)
{return a - b;
}int add1(int a, int b, int c)
{return a * 10 + b - c;
}int main()
{//调整参数顺序(没什么用处)auto e = bind(add, _1, _2);cout<<e(2, 3)<<endl;auto x = bind(add, _2, _1);cout << x(2, 3) << endl;//调整参数个数(常用)//直接绑定第1、2、3的参数,传参的时候只用传未绑定的参数auto c = bind(add1, 10, _1, _2);cout << c(1,2) << endl;auto d = bind(add1, _1, 10, _2);cout << d(1, 2) << endl;auto w = bind(add1, _1, _2, 10);cout << w(1, 2) << endl;//bind常用于绑定固定参数//function<double(Plus*,double, double)> f = &Plus::plusd;function<double(double, double)> f = bind(&Plus::plusd, Plus(), _1, _2);cout<<f(1, 2)<<endl;}

        总的来看,bind有用的功能主要是控制函数参数个数常用于绑定一些固定的参数

版权声明:

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

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

热搜词