#pragma once #include <boost/bind.hpp> #include <string> #include <iostream> #include <conio.h> #include <vector> #include <algorithm> using namespace std; using namespace boost; //bind是C++98标准库中函数适配器bind1st、bind2nd的泛化和增强,可以适配任意的可调用对象,包括函数,函数指针,函数引用,成员函数指针和函数对象。bind远远的超越了STL中的函数绑定其(bind1st/bind2nd),可以绑定最多9个函数参数,而且对绑定对象的要求很低,可以在没有result_type内部类型定义的情况下完成对函数对象的绑定。bind库很好的增强了标准库的功能。 //绑定普通函数(函数,函数指针) int f(int a,int b){return a+b;}//二元函数 int g(int a,int b,int c){return a+b*c;}//三元函数 void test1() { //绑定表达式没有使用占位符 cout<<bind(f,1,2)()<<endl;//3 bind(f,1,2)返回一无参调用的函数对象,等价于f(1,2) cout<<bind(g,1,2,3)()<<endl;//7 同上 cout<<f(1,2)<<" "<<g(1,2,3)<<endl;//3 7 //使用占位符 int x=0,y=1,z=2; cout<<bind(f,_1,9)(x)<<endl;//9 ==>>f(x,9) cout<<bind(f,_1,_2)(x,y)<<endl;//1 ==>>f(x,y) cout<<bind(f,_2,_1)(x,y)<<endl;//1 ==>>f(y,x) cout<<bind(f,_1,_1)(x,y)<<endl;//0 ==>>f(x,x);y参数被忽略了 cout<<bind(g,_1,8,_2)(x,y)<<endl;//8 ==>>g(x,8,y) cout<<bind(g,_3,_2,_2)(x,y,z)<<endl;//3 ==>>g(z,y,y);x参数被忽略了 //必须在绑定表达式中提供函数要求的所有参数,无论是真实参数还是占位符均可以。但不能使用超过函数参数数量的占位符,eg:在绑定f是不能使用_3;在绑定g是不能使用_4;也不能写bind(f,_1,_2,_2)这样的形式,否则会导致编译错误 } //绑定函数指针 用法同上,可以还有占位符,也可以不使用占位符 typedef int (*f_type)(int,int);//函数指针定义 typedef int(*g_type)(int,int,int);//函数指针定义 void test2() { f_type pf=f; g_type pg=g; int x=1,y=2,z=3; cout<<bind(pf,_1,9)(x)<<endl;//10 ==>>(*pf)(x,9) cout<<bind(pg,_3,_2,_2)(x,y,z)<<endl;//7 ==>>(*pg)(z,y,y) } //绑定成员函数 void test3() { //类的成员函数不同于普通函数,因为成员函数指针不能直接调用opreator(),它必须被绑定到一个对象或者指针上,然后才能得到this指针进而调用成员函数。因此bind需要牺牲一个占位符的位置(意味着使用成员函数是只能最多绑定8个参数),要求用户提供一个类的实例,引用或者指针,通过对象最为第一个参数来调用成员函数。 struct demo//使用struct仅仅是为了方便,不必写出public { int f(int a,int b){return a+b;} }; demo a,&ra=a,*p=&a;//类的实例对象,引用,指针 cout<<bind(&demo::f,a,_1,20)(10)<<endl;//30 ==>>a.f(10,20) cout<<bind(&demo::f,ra,_2,_1)(10,20)<<endl;//30 ==>>ra.f(20,10) cout<<bind(&demo::f,p,_1,_2)(10,20)<<endl;//30 ==>p->f(10,20) //注意:我们必须在成员函数前加上取地址操作符&,表明这是一个成员函数指针,否则会无法通过编译,这是与绑定函数的一个小小的不同。 //bind能够绑定成员函数,这是个非常有用的功能,它可以代替标准库中令人迷惑的mem_fun和mem_fun_ref绑定器,用来配合标准算法操作容器中的对象。下面试使用bind搭配标准算法for_each用来调用容器中所有对象的print()函数: struct point { int x,y; point(int a=0,int b=0):x(a),y(b){} void print(){cout<<"("<<x<<","<<y<<") ";} }; vector<point>v(2,3); for_each(v.begin(),v.end(),bind(&point::print,_1)); //(3,0) (3,0) //bind同样支持绑定虚拟成员函数,用法与非虚拟成员函数相同,虚函数的行为将有实际调用发生时的实例来决定。 } //绑定函数对象 void test4() { //如果函数对象有内部类型定义result_type,那么bind可以自动推导出返回值的类型,用法与绑定普通函数一样。但如果函数对象没有定义result_type,则需要在绑定形式上做一点改动,用模板参数指明返回类型,eg bind<result_type>(Functor,...) //标准库和boost库中大部分函数对象都具有result_type定义,因此不需要特别的形式就可以直接使用bind int x=5,y=2; //cout<<bind(greater<int>(),_1,10)(x)<<endl;//0 检查x>10 //cout<<bind(plus<int>(),_1,_2)(x,y)<<endl;//7 执行x+y //cout<<bind(modulus<int>(),_1,3)(x)<<endl;//2 执行 x%3 //上面三行在vs2010中没问题,但在vs2008中有问题 //对于自定义函数对象,如果没有result_type类型定义,eg struct f { int operator()(int a,int b) { return a+b;} }; cout<<bind<int>(f(),_1,_2)(x,y)<<endl;//7 //这种写法多少会有些不方便,因此,在编写自己的函数对象是,最好遵循规范为它们增加内部typedef result_type,这样将使函数对象与许多其他标准库和boost库组件良好配合工作。 } //绑定成员变量 void test5() { struct point { int x,y; point(int a=0,int b=0):x(a),y(b){} void print(){cout<<"("<<x<<","<<y<<") ";} }; vector<point>v(2,3); vector<int>v2(2); transform(v.begin(),v.end(),v2.begin(),bind(&point::x,_1)); } //使用ref库 void test6() {//bind采用拷贝的方式存储绑定对象和参数,这意味着绑定表达式中的每个变量都会有一份拷贝,如果函数对象或值参数很大,拷贝代价很高,或者无法拷贝,那么bind的使用就会受到限制。因此bind库可以搭配ref库使用,ref库包装了对象的引用,可以让bind存储对象引用实例,从而降低了拷贝的代价。(必须包装引用的对象存在,其没有销毁) int x=10; cout<<bind(g,_1,cref(x),ref(x))(10)<<endl;//110 } void test(char t) { cout<<"press key====="<<t<<endl; switch (t) { case '1':test1();break; case '2':test2();break; case '3':test3();break; case '4':test4();break; case '5':test5();break; case '6':test6();break; case 27: case 'q':exit(0);break; default: cout<<"default "<<t<<endl;break; } } int main() { while(1) { test(getch()); } return 0; }
官网实例