简介
C++ STL中的绑定器
- bind1st:operator()的第一个形参变量绑定一个确定的值。
- bind2nd:operator()的第二个形参变量绑定一个确定的值。
C++ Boost库
C++的Boost库中引入了bind绑定器和function函数对象机制。
lambda表达式
lambda表达式由底层依赖函数对象的机制实现。
C++ STL中的绑定器
初识band1st和band2nd
band1st和band2nd本身还是一个函数对象。
将STL中内置的二元函数对象转化为一元函数对象使用。
#include<iostream> #include<functional> #include<vector> #include<algorithm> #include<time.h> using namespace std; template<typename Container> void showContainer(Container &con){ //由于编译的原因,所以需要加上typename,防止无法识别Container类型 typename Container::iterator 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++) { //产生1~100之间的随机数 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); // bind1st和bind2nd可以将二元函数对象转化为一元函数对象,也就是说传入的默认值对应二元函数对象的形参 // 寻找第一个小于70的索引,原序列按照从大到小排序 return 70>*it // auto it = find_if(vec.begin(), vec.end(), bind1st(greater<int>(), 70)); // 寻找第一个小于70的索引,原序列按照从大到小排序 return *it<70 auto it = find_if(vec.begin(), vec.end(), bind2nd(less<int>(), 70)); if(it!=vec.end()) { vec.insert(it, 70); } showContainer(vec); return 0; }
自己实现band1st和find_if
#include<iostream> #include<functional> #include<vector> #include<algorithm> #include<time.h> using namespace std; template<typename Container> void showContainer(Container &con){ //由于编译的原因,所以需要加上typename,防止无法识别Container类型 typename Container::iterator it = con.begin(); for (; it != con.end();it++) { cout << *it << " "; } cout << endl; } template <typename Compare, typename T> class _mybind1st{ public: _mybind1st(Compare comp,T val): _comp(comp),_val(val){} 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) { return _mybind1st<Compare, T>(comp, val); } template<typename Iterator,typename Compare> Iterator my_find_if(Iterator first,Iterator last,Compare comp){ for (; first != last;first++){ //comp.operator()(*first) if(comp(*first)){ return first; } } return last; } int main(){ vector<int> vec; srand(time(nullptr)); for (int i = 0; i < 20;i++) { //产生1~100之间的随机数 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 it = my_find_if(vec.begin(), vec.end(), mybind1st(greater<int>(), 70)); // auto it = my_find_if(vec.begin(), vec.end(), bind2nd(less<int>(), 70)); if(it!=vec.end()) { vec.insert(it, 70); } showContainer(vec); return 0; }
bind函数
C++11中的bind绑定器的返回结果还是一个函数对象。
初识bind函数
#include<iostream> #include<string> #include<functional> using namespace std; 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,world")(); cout << bind(sum, 10, 20)() << endl; //bind使用函数对象的时候,必须要利用函数对象才能使用 cout << bind(&Test::sum, Test(), 10, 20)()<<endl; // placeholders是占位符 bind(hello, placeholders::_1)("hello,bind2!"); bind(sum, placeholders::_1, placeholders::_2)(1, 3); function<void(string)> func1 = bind(hello, placeholders::_1); func1("hello,china!"); func1("hello,shanghai!"); return 0; }
bind和function结合多线程使用
#include<iostream> #include<string> #include<thread> #include<vector> #include<functional> using namespace std; class Thread{ public: Thread(function<void()> func) : _func(func){}; thread start() { thread t(_func); return t; } private: function<void()> _func; }; class ThreadPool { public: ThreadPool(){}; ~ThreadPool(){ for (int i = 0;i<_pool.size();i++) { delete _pool[i]; } }; void startPool(int size) { for (int i = 0; i < size; i++) { _pool.push_back(new Thread(bind(&ThreadPool::runThread,this,i))); } for (int i = 0; i < size; i++) { _handler.push_back(_pool[i] -> start()); } for (int i = 0; i < size;i++) { _handler[i].join(); } } private: vector<Thread*> _pool; vector<thread> _handler; void runThread(int id) { cout << "call run Thread id :" << id << endl; } }; int main() { ThreadPool pool; pool.startPool(10); return 0; }
代码打印结果,由于是多线程,所以打印结果是乱序的。
call run Thread id :call run Thread id :call run Thread id :2call run Thread id :5 call run Thread id :61 call run Thread id :9 call run Thread id :4 call run Thread id :8 0 call run Thread id : call run Thread id :37
C++中的lambda表达式
函数对象的主要缺点:需要先定义函数,并初始化函数对象才能被使用。
C++ 11 中的 Lambda 表达式用于定义并创建匿名的函数对象,以简化编程工作。
Lambda 的语法形式如下:
[captures](params) -> return_type { body };
Lambda 主要分为五个部分,对应为:
[捕获列表] (函数参数) mutable 或 exception 声明 -> 返回值类型 {函数体}
上式lambda表达式中->可以省略。
捕获列表是 Lambda 表达式最有意思的地方,这里重点介绍下捕获列表。
捕获列表,用来说明外部变量的访问方式,外部变量访问方式说明符可以是 = 或 & ,表示函数体中用到的、定义在外面的变量在函数体中是否允许被改变。= 表示值传递,不允许改变。& 表示引用传递,允许改变。
包括下面几种形式:
1、[ ] 表示不捕获任何变量
2、[=] 表示按值传递的方法捕获父作用域的所有变量
3、[&] 表示按引用传递的方法捕获父作用域的所有变量
4、[=, &a] 表示按值传递的方法捕获父作用域的所有变量,但按引用传递的方法捕获变量a
5、[&, a] 表示按引用传递的方法捕获父作用域的所有变量,但按值传递的方法捕获变量a
6、[this] 捕获外部的指针
更多lambda表达式的介绍可以参考C++ 之 Lambda 表达式。
mutable在lambda表达式返回类型前加上,可以在以值传递的形式上修改以值传递的变量值。
C++中的函数对象
function的作用在于:绑定器、函数对象、lambda表达式,它们只能使用在一条语句中。
初识function
#include<iostream> #include<string> #include<algorithm> #include<functional> #include<ctime> 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; } class Test{ public: void hello(string str){ cout << str; } }; int main(){ /* function函数的使用方法,function<typename(typename1,...)> xxx=yyy; typename表示函数的返回类型,typename_1表示寒暑的参数类型,xxx表示function重命名的函数,yyy表示原来的函数 */ // 调用函数hello1(),function使用的是函数类型 function<void()> func1 = hello1; // 调用函数hello1(),function使用的是函数指针类型 // function<void(*)> func1 = hello1; // 本质上和hello1()没有区别,调用了func1对象()重载函数->hello1.operator() func1(); function<void(string)> func2 = hello2; func2("hello2!"); function<int(int, int)> func3 = sum; cout << func3(10, 20) << endl; function<int(int, int)> func4 = [](int a, int b)->int{ return a + b; }; cout << func4(10, 20); function<void(Test*, string)> func5 = &Test::hello; func5(&Test(), "call Test::hello!"); return 0; }
自定义实现function
本质上是实现一个类,利用构造函数和()操作符重载的功能是实现函数绑定。
#include<iostream> #include<functional> #include<string> 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: //函数返回的指针参数类型 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: // 函数返回的指针参数类型 using PFUNC = R (*)(A1,A2); myfunction(PFUNC pfunc) : _pfunc(pfunc){}; R operator()(A1 arg1,A2 arg2) { return _pfunc(arg1,arg2); } private: PFUNC _pfunc; }; */ // ...表示可变参数类型个数,和上面两个类的功能是一样的 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(){ //就是构造函数重命名了hello函数 myfunction<void(string)> func1(hello); func1("hello1"); myfunction<int(int, int)> func2(sum); cout << func2(2, 3) << endl; return 0; }