这篇文章主要介绍了C++11中bind绑定器和function函数对象实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C++11中bind绑定器和function函数对象实例分析文章都会有所收获,下面我们一起来看看吧。
一. 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++11中bind绑定器和function函数对象实例分析”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注恰卡网行业资讯频道。