当前位置:编程学习 > C/C++ >>

[Boost基础]函数与回调——bind绑定

[cpp] 
#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存储对象引用实例,从而降低了拷贝的代价。(必须
补充:软件开发 , C++ ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,