一. bind1st和bind2nd
1.c++ stl中的绑定器
- bind1st:operator()的第一个形参变量绑定成一个确定的值
- bind2nd:operator()的第二个形参变量绑定成一个确定的值
c++11从boost库中引入了bind绑定器和function函数对象机制
bind可用于给多元函数降元:bind + 二元函数对象 = 一元函数对象
#include<iostream> #include<vector> #include<functional> #include<algorithm>//泛型算法 #include<ctime> using namespace std; template<typename container> void showcontainer(container& con) { //typename container::iterator it=con.begin(); auto it = con.begin(); for (; it != con.end(); ++it) { cout << *it << " "; } cout << endl; } int main() { vector<int> vec; srand(time(nullptr)); for (int i = 0; i < 20; ++i) { vec.push_back(rand() % 100 + 1); } showcontainer(vec); sort(vec.begin(), vec.end());//默认从小到大排序 showcontainer(vec); //greater需要二元函数对象 sort(vec.begin(), vec.end(), greater<int>());//从大到小排序 showcontainer(vec); /* 把70按顺序插入到vec容器中 ->找第一个小于70的数字 operator()(const t &val) greater a>b less a<b 绑定器+二元函数对象=》一元函数对象 bind1st:+greater bool operator()(70,const_ty&_right) bind2nd:+less bool operator()(const_ty &_left,70) */ auto it1 = find_if(vec.begin(), vec.end(), bind1st(greater<int>(), 70)); if (it1 != vec.end()) { vec.insert(it1, 70); } showcontainer(vec); return 0; }
2.bind1st和bind2nd的底层原理实现
绑定器本身是一个函数对象
#include<iostream> #include<vector> #include<functional> #include<algorithm> #include<ctime> using namespace std; template<typename container> void showcontainer(container& con) { auto it = con.begin(); for (; it != con.end(); ++it) { cout << *it << " "; } cout << endl; } //遍历两个迭代器之间的元素,如果满足函数对象的运算,就返回当前的迭代器,如果都不满足就返回end template<typename iterator,typename compare> iterator my_find_if(iterator first, iterator last, compare comp) { //这里传入的comp是封装好的一元函数对象 for (; first != last; ++first) { if (comp(*first))//获取容器的一个元素 { return first; } } return last; } template<typename compare,typename t> class _mybind1st//绑定器是函数对象的一个应用 { public: //这里传入的comp是二元函数对象 _mybind1st(compare comp,t val) :_comp(comp),_val(val){} //通过重载operator()把二元函数对象封装为一元函数对象 bool operator()(const t& second) { return _comp(_val, second); } private: compare _comp; t _val; }; template<typename compare,typename t> _mybind1st<compare, t> mybind1st(compare comp, const t& val) { //直接使用函数模板,好处是可以进行类型的推演 //这里传入的comp是一个二元函数对象 //通过二元函数对象构造一元函数对象 //绑定器本身是一个函数对象,也就是重载了operator() return _mybind1st<compare, t>(comp, val); } int main() { vector<int> vec; srand(time(nullptr)); for (int i = 0; i < 20; ++i) { vec.push_back(rand() % 100 + 1); } showcontainer(vec); sort(vec.begin(), vec.end());//默认从小到大排序 showcontainer(vec); //greater需要二元函数对象 sort(vec.begin(), vec.end(), greater<int>());//从大到小排序 showcontainer(vec); auto it1 = my_find_if(vec.begin(), vec.end(), mybind1st(greater<int>(), 70)); if (it1 != vec.end()) { vec.insert(it1, 70); } showcontainer(vec); return 0; }
二. 模板的完全特例化和非完全特例化
有完全特例化优先匹配完全特例化,有部分特例化就匹配部分特例化,没有的话就从原模板自己实例化
#include<iostream> using namespace std; template<typename t> class vector { public: vector() { cout << "call vector template init" << endl; } }; //对char*类型提供完全特例化版本 template<> class vector<char*> { public: vector() { cout << "call vector<char*> init" << endl; } }; //对指针类型提供的部分特例化版本(部分:只知道是个指针,但是指针的类型是什么不知道) template<typename ty> class vector<ty*> { public: vector() { cout << "call vector<ty*> init" << endl; } }; //指针函数指针(有返回值,有两个形参变量)提供的部分特例化 template<typename r,typename a1,typename a2> class vector<r(*)(a1, a2)> { public: vector() { cout << "call vector<r(*)(a1,a2)> init" << endl; } }; //针对函数(有一个返回值,有两个形参变量)类型提供的部分特例化 template<typename r, typename a1, typename a2> class vector<r(a1, a2)> { public: vector() { cout << "call vector<r(a1,a2)> init" << endl; } }; int sum(int a, int b) { return a + b; } int main() { vector<int> vec1; vector<char*> vec2; vector<int*> vec3; vector<int(*)(int, int)> vec4; vector<int(int, int)> vec5; //注意区分函数类型和函数指针类型 typedef int(*pfunc1)(int, int); pfunc1 pfunc1 = sum; cout << pfunc1(10, 20) << endl; typedef int pfunc2(int, int); pfunc2* pfunc2 = sum; cout << (*pfunc2)(10, 20) << endl; return 0; }
#include<iostream> #include<typeinfo> using namespace std; //t包含了所有大的类型 template<typename t> void func(t a) { cout << typeid(t).name() << endl; } int sum(int a, int b) { return a + b; } //把所有形参类型都取出来 template<typename r, typename a1, typename a2> void func2(r(*a)(a1, a2)) { cout << typeid(r).name() << endl; cout << typeid(a1).name() << endl; cout << typeid(a2).name() << endl; } template<typename r,typename t,typename a1,typename a2> void func3(r(t::*a)(a1, a2)) { cout << typeid(r).name() << endl; cout << typeid(t).name() << endl; cout << typeid(a1).name() << endl; cout << typeid(a2).name() << endl; } class test { public: int sum(int a, int b) { return a + b; } }; int main() { //func(10);//int //func("aaa");//const char * func(sum); func2(sum); func3(&test::sum); return 0; }
三. function函数对象
绑定器,函数对象,lambda表达式本质上都是函数对象,只能使用在一条语句中,但是如果想要在多条语句中使用,就需要function
使用function函数需要注意:
- 用函数类型实例化function;
- 通过function调用
operator()
函数的时候,需要根据函数类型传入相应的参数。
#include<iostream> #include<functional> using namespace std; void hello1() { cout << "hello world!" << endl; } void hello2(string str) { cout << str << endl; } int sum(int a, int b) { return a + b; } int main() { //从function的模板定义处,看到希望用一个函数类型实例化function function<void()> func1 = hello1; func1();//func1.operator() => hello1() function<void(string)> func2 = hello2; func2("hello hello2!"); function<int(int, int)> func3 = sum; cout << func3(2, 3) << endl; function<int(int, int)> func4 = [](int a, int b)->int {return a + b; }; cout << func4(3, 4) << endl; return 0; }
function不仅可以留下普通全局函数的类型,对于类的成员方法也可以进行类型保留:
#include<iostream> #include<functional> using namespace std; class test { public://必须依赖一个对象void(test::*pfunc)(string) void hello(string str) { cout << str << endl; } }; int main() { //成员方法一经编译都会多一个当前类型的this指针 function<void (test*, string)> func = &test::hello; test t; //对于成员方法的调用需要依赖一个成员对象 func(&t, "call test::hello!"); return 0; }
function的特点:可以把所有函数、绑定器、函数对象和lambda表达式的类型保留起来,在其他地方都可以使用。否则绑定器、lambda表达式就只能使用在语句中。
#include<iostream> #include<functional> #include<map> using namespace std; void doshowallbooks(){ cout << "查看所有书籍信息" << endl; } void doborrow() { cout << "借书" << endl; } void doback() { cout << "还书" << endl; } void doquerybooks() { cout << "查询书籍" << endl; } void dologinout() { cout << "注销" << endl; } int main() { int choice = 0; //使用function函数对象完成 map<int, function<void()>> actionmap; actionmap.insert({ 1,doshowallbooks }); actionmap.insert({ 2,doborrow }); actionmap.insert({ 3,doback }); actionmap.insert({ 4,doquerybooks }); actionmap.insert({ 5,dologinout }); for (;;) { cout << "------------------" << endl; cout << "1.查看所有书籍信息" << endl; cout << "2.借书" << endl; cout << "3.还书" << endl; cout << "4.查询书籍" << endl; cout << "5.注销" << endl; cout << "------------------" << endl; cout << "请选择:"; cin >> choice; auto it = actionmap.find(choice); if (it == actionmap.end()) { cout << "输入数字无效,重新选择" << endl; } else { it->second(); } //不好,因为这块代码无法闭合,无法做到“开-闭”原则,也就是说这块代码随着需求的更改需要一直改,永远也闭合不了,避免不了要产生很多问题 /* switch(choice) { case 1:break; case 2:break; case 3:break; case 4:break; case 5:break; default:break; } */ } return 0; }
function的实现原理:
#include<iostream> #include<functional> using namespace std; void hello(string str) { cout << str << endl; } int sum(int a, int b) { return a + b; } template<typename fty> class myfunction{}; /* template<typename r,typename a1> class myfunction<r(a1)> { public: //typedef r(*pfunc)(a1); using pfunc = r(*)(a1); myfunction(pfunc pfunc):_pfunc(pfunc){} r operator()(a1 arg) { return _pfunc(arg); } private: pfunc _pfunc; }; template<typename r, typename a1,typename a2> class myfunction<r(a1,a2)> { public: //typedef r(*pfunc)(a1); using pfunc = r(*)(a1,a2); myfunction(pfunc pfunc) :_pfunc(pfunc) {} r operator()(a1 arg1,a2 arg2) { return _pfunc(arg1,arg2); } private: pfunc _pfunc; }; */ //...表示可变参,a表示的是一组1类型,个数任意 template<typename r, typename... a> class myfunction<r(a...)> { public: using pfunc = r(*)(a...); myfunction(pfunc pfunc) :_pfunc(pfunc) {} r operator()(a... arg) { return _pfunc(arg...); } private: pfunc _pfunc; }; int main() { myfunction<void(string)> func1(hello); func1("hello world"); myfunction<int(int, int)> func2(sum); cout << func2(10, 20) << endl; return 0; }
四. bind和function实现线程池
#include<iostream> #include<functional> using namespace std; using namespace placeholders; //c++11 bind 绑定器=>返回的结果是一个函数对象 void hello(string str) { cout << str << endl; } int sum(int a, int b) { return a + b; } class test { public: int sum(int a, int b) { return a + b; } }; int main() { //bind是函数模板,可以自动推演模板类型参数 bind(hello, "hello bind!")(); cout << bind(sum, 20, 30)() << endl; cout << bind(&test::sum, test(), 20, 30)() << endl; //function只接受一个类型,绑定器可以给相应的函数绑定固定的参数,绑定器只能使用在语句当中 //参数占位符,绑定器出了语句,无法继续使用 bind(hello, _1)("hello bind 2"); cout << bind(sum, _1, _2)(20, 30) << endl; //此处把bind返回的绑定器binder就复用起来了 function<void(string)> func1 = bind(hello, _1); func1("hello china!"); func1("hello shan xi!"); func1("hello da li!"); }
#include<iostream> #include<functional> #include<thread> #include<vector> using namespace std; using namespace placeholders; //线程类 class thread { public: thread(function<void(int)> func,int no):_func(func),_no(no){} thread start() { thread t(_func,_no); return t; } private: function<void(int)> _func; int _no; }; //线程池类 class threadpool { public: threadpool(){} ~threadpool() { //释放thread对象占用的堆资源 for (int i = 0; i < _pool.size(); i++) { delete _pool[i]; } } //开启线程池 void startpool(int size) { for (int i = 0; i < size; i++) { //不管是c++里面的thread还是linux里面的pthread需要的线程函数都是一个c函数,是不能够使用成员方法的,因为它是c的函数类型,不可能把成员方法的函数指针给一个c的函数指针,接收不了。所以就需要绑定,把runinthread所依赖的参数全部绑定 _pool.push_back(new thread(bind(&threadpool::runinthread, this, _1),i)); } for (int i = 0; i < size; i++) { _handler.push_back(_pool[i]->start()); } for (thread& t : _handler) { t.join(); } } private: vector<thread*> _pool; vector<thread> _handler; //把runinthread这个成员方法充当线程函数 void runinthread(int id) { cout << "call runinthread! id:" << id << endl; } }; int main() { threadpool pool; pool.startpool(10); return 0; }
五. lambda表达式
- 函数对象的应用:使用在泛型算法参数传递、比较性质、自定义操作、优先级队列和智能指针
- 函数对象的缺点:需要先定义一个函数对象类型,但是类型定义完后可能只是用在了定义的地方,后面可能不会再用了,没有必要为了需要一个函数对象定义一个类型,这个类型就永远在代码当中。
c++11函数对象的升级版 => lambda表达式:
- lambda表达式:底层依赖函数对象的机制实现的。
- lambda表达式语法:[捕获外部变量](形参列表) ->返回值{操作代码};
如果lambda表达式的返回值不需要,那么“->返回值”可以省略
[捕获外部变量]
- [ ]:表示不捕获任何外部变量
- [=]:以传值的方式捕获外部的所有变量
- [&]:以传引用的方式捕获外部的所有变量[this]:捕获外部的this指针
- [=,&a]:以传值的方式捕获外部的所有变量,但是a变量以传引用的方式捕获
- [a,b]:以传值的方式捕获外部变量a和b
- [a,&b]:a以值传递捕获,b以传引用的方式捕获
1.lambda表达式的实现原理
#include<iostream> using namespace std; template<typename t=void> class testlambda01 { public: void operator()() { cout << "hello world" << endl; } }; template<typename t = int> class testlambda02 { public: testlambda02() {} int operator()(int a, int b) { return a + b; } }; template<typename t = int> class testlambda03 { public: testlambda03(int a,int b):ma(a),mb(b){} void operator()()const { int tmp = ma; ma = mb; mb = tmp; } private: mutable int ma; mutable int mb; }; class testlambda04 { public: testlambda04(int &a,int &b):ma(a),mb(b){} void operator()()const { int tmp = ma; ma = mb; mb = tmp; } private: int& ma; int& mb; }; int main() { auto func1 = []()->void {cout << "hello world" << endl; }; func1(); auto func2 = [](int a, int b)->int {return a + b; }; cout << func2(20, 30) << endl; int a = 10; int b = 20; //按值传递a,b值未被改变 auto func3 = [a, b]()mutable { int tmp = a; a = b; b = tmp; }; func3(); cout << "a:" << a << " b:" << b << endl; //传引用值a,b值被改变 auto func4 = [&]() { int tmp = a; a = b; b = tmp; }; func4(); cout << "a:" << a << " b:" << b << endl; cout << "--------------------" << endl; testlambda01<> t1; t1(); testlambda02<> t2; cout << t2(20, 30) << endl; testlambda03<> t3(a,b); t3(); cout << "a:" << a << " b:" << b << endl; testlambda04 t4(a,b); t4(); cout << "a:" << a << " b:" << b << endl; return 0; }
mutable
:成员变量本身也不是常量,只不过在常方法中this指针被修饰成const,在声明成员变量前加mutable
,可以在const
方法中修改普通的成员变量
lambda表达式后面修饰mutable相当于在它的所有成员变量添加一个mutable修饰。
2.lambda表达式的应用实践
lambda表达式应用于泛型算法:
#include<iostream> #include<vector> #include<algorithm> using namespace std; int main() { vector<int> vec; for (int i = 0; i < 20; ++i) { vec.push_back(rand() % 100 + 1); } sort(vec.begin(), vec.end(), [](int a, int b)->bool { return a > b; }); for (int val : vec) { cout << val << " "; } cout << endl; //65按序插入序列 要找一个小于65的数字 auto it = find_if(vec.begin(), vec.end(), [](int a)->bool {return a < 65; }); if (it != vec.end()) { vec.insert(it, 65); } for (int val : vec) { cout << val << " "; } cout << endl; for_each(vec.begin(), vec.end(), [](int a) { if (a % 2 == 0) cout << a << " "; }); cout << endl; return 0; }
既然lambda表达式只能使用在语句中,如果想跨语句使用之前定义好的lambda表达式,采用function类型来表示函数对象的类型。
哈希表的应用:
#include<iostream> #include<vector> #include<map> #include<functional> using namespace std; int main() { //auto只能出现在根据右边表达式推导左边的类型,只能使用在函数的局部作用域的范围之内 //预先lambda表达式不知道需要先存储lambda表达式类型 map<int, function<int(int, int)>> caculatemap; caculatemap[1] = [](int a, int b)->int {return a + b; }; caculatemap[2] = [](int a, int b)->int {return a - b; }; caculatemap[3] = [](int a, int b)->int {return a * b; }; caculatemap[4] = [](int a, int b)->int {return a / b; }; cout << "请选择"; int choice; cin >> choice; cout << caculatemap[choice](10, 15) << endl; return 0; }
智能指针自定义删除器:
#include<iostream> #include<vector> #include<functional> using namespace std; int main() { unique_ptr<file, function<void(file*)>> ptr1(fopen("data.txt", "w"), [](file* pf) {fclose(pf); }); }
传入函数对象使得容器元素按照指定方式排列:
#include<iostream> #include<vector> #include<functional> #include <queue> using namespace std; class data { public: data(int val1=10,int val2=10):ma(val1),mb(val2){} int ma; int mb; }; int main() { //优先级队列 //priority_queue<data> queue; using func = function<bool(data&, data&)>; priority_queue<data, vector<data>, func> maxheap([](data& d1, data& d2)->bool { return d1.mb > d2.mb; }); maxheap.push(data(10, 20)); maxheap.push(data(15, 15)); maxheap.push(data(20, 10)); }
到此这篇关于c++11中bind绑定器和function函数对象介绍的文章就介绍到这了,更多相关c++bind绑定器内容请搜索<计算机技术网(www.ctvol.com)!!>以前的文章或继续浏览下面的相关文章希望大家以后多多支持<计算机技术网(www.ctvol.com)!!>!
需要了解更多c/c++开发分享C++11中bind绑定器和function函数对象介绍,都可以关注C/C++技术分享栏目—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/1156154.html