boost::bind 函数绑定

当我们使用函数时习惯于C函数的格式,即如下形式
resulttype funname( arglist );
返回值类型 函数名( 参数列表 );

在Boost.Function中,我们可以方便的定义定义函数对象。不过在定义用来表示类成员函数的函数对象时
第一个参数是类指针。而且在调用时,要传入一个类实例的指针。这样用起来并不是很方便,因为调用者
要知道类实例。这实际上没有实现解耦。而解耦是我们使用回调或委托设计的一个目标。

为了解决这个问题,我们要使用Boost.Bind库

Boost.Bind是一个函数对象工厂。他用来产生我们需要的函数对象。好了,有了它,你可以在你设计中大
量使用Boost.Function。不用再去定义类成员函数形式的函数对象啦,只用定义普通函数对象。

一个简单的例子

class CExample
{
public:
    bool printstr( const std::string &str )
    {
        std::cout << "CExample::printstr" << str << std::endl;
        return true;
    }
};

//定义一个函数对象
boost::function< bool ( const std::string& ) > printstr;

//用Boost.Bind创建一个函数对象,赋给printstr
CExample example;
printstr = boost::bind( &CExample::printstr, &example, _1 );

好了,我们创建了一个函数对象,而且调用时不再需要类实例拉。用Boost.Function和Boost.Bind大大
的简化了Command模式的实现。

在上面的例子中要个古怪的对象"_1"。这个叫做站位符,他代表这个位置有个参数,但现在还不知道参
数是什么。_1代表参数列表中的第一个位置上的参数。Boost.Bind一共定义了9个站位符对象。如下
_1,_2,_3,_4,_5,_6,_7,_8,_9。分别代表参数列表中位子。

Boost.Bind产生的函数对象可以直接使用,利用上面的例子。

bool b = boost::bind( &CExample::printstr, &example, _1 )( "Hello World" );

Boost::bind


一 Boost::bind

在STL中,我们经常需要使用bind1st,bind2st函数绑定器和fun_ptr,mem_fun等函数适配器,这些函数绑定器和函数适配器使用起来比较麻

烦,需要根据是全局函数还是类的成员函数,是一个参数还是多个参数等做出不同的选择,而且有些情况使用STL提供的不能满足要求,所以如

果可以我们最好使用boost提供的bind,它提供了统一的接口,提供了更多的支持,比如说它增加了shared_ptr,虚函数,类成员的绑定。

二 源码剖析

1) bind1st,bind2st函数绑定器,把二元函数对象变为一元函数对象。
2) mem_fun,把成员函数变为函数对象。
3) fun_ptr,把一般的全局函数变为函数对象。
4) boost::bind(),包含了以上所有的功能。


三 实例

1)区别与mem_fun和fun_ptr

#include <functional>
#include <iostream>
#include < string>
#include "boost/bind.hpp"
class some_class
{
public:
void print_string(const std::string& s)const
{
std::cout << s << '\n';
}

void print_classname()
{
std::cout << "some_class" << std::endl;
}

}
;
void print_string( const std:: string s)
{ std::cout << s << '\n';
}

void print_functionname()
{
std::cout << "Print_functionname" <<std::endl;
}

int main()
{
std::ptr_fun(&print_string)("hello1");
//std::ptr_fun<void>(&print_functionname);
some_class sc0;
std::mem_fun_ref(&some_class::print_classname)(sc0);
std::mem_fun_ref<void,some_class>(&some_class::print_classname)(sc0);
//std::mem_fun1_ref<void,some_class,const std::stirng>(&some_class::print_string)(sc0,"hello2");

(boost::bind(&print_string,_1))("Hello func!");
boost::bind(&print_functionname);
some_class sc;
(boost::bind(&some_class::print_classname,_1)(sc));
(boost::bind(&some_class::print_string,_1,_2))(sc,"Hello member!");
}

2)区别与bind1st和bind2st

#include <functional>
#include <iostream>
#include < string>
#include <vector>
#include <algorithm>
#include "boost/bind.hpp"
void main()
{
std::vector<int> ints;
ints.push_back(7);
ints.push_back(4);
ints.push_back(12);
ints.push_back(10);
int count=std::count_if(ints.begin(),
ints.end(),
boost::bind(std::logical_and<bool>(),boost::bind(std::greater<int>(),_1,5),boost::bind(std::less_equal<int>(),_1,10))
);
std::cout << count << '\n';
std::vector<int>::iterator int_it=std::find_if(ints.begin(),
ints.end(),
boost::bind(std::logical_and<bool>(),boost::bind(std::greater<int>(),_1,5),boost::bind(std::less_equal<int>(),_1,10))
);
if (int_it!=ints.end())
{ std::cout << *int_it << '\n';}

}

3)区别传ref和传instance

// bind instance or reference
#include <functional>
#include <iostream>
#include < string>
#include <vector>
#include <algorithm>
#include "boost/bind.hpp"
class tracer
{
public:
tracer() { std::cout << "tracer::tracer()\n"; }
tracer(const tracer& other) { std::cout << "tracer::tracer(const tracer& other)\n"; }
tracer&operator=(const tracer& other)
{ std::cout << "tracer& tracer::operator=(const tracer& other)\n";return *this; }
~tracer() { std::cout << "tracer::~tracer()\n";
}

void print(const std::string& s)const
{ std::cout << s << '\n'; }
}
;

void main()
{
tracer t;
boost::bind(&tracer::print,t,_1)(std::string("I'm called on a copy of t\n"));
tracer t1;
boost::bind(&tracer::print,boost::ref(t1),_1)( std::string("I'm called directly on t\n"));

}

4)绑定虚函数

// bind vitual class function
#include <functional>
#include <iostream>
#include < string>
#include <vector>
#include <algorithm>
#include "boost/bind.hpp"
class base {
public:
virtualvoid print()const
{ std::cout << "I am base.\n";
}

virtual ~base(){}
}
;
class derived : public base
{
public:
void print()const
{ std::cout << "I am derived.\n"; }
}
;

void main()
{
derived d;
base b;
boost::bind(&base::print,_1)(b);
boost::bind(&base::print,_1)(d);
}

5)绑定成员变量

// bind class's member
#include <functional>
#include <iostream>
#include < string>
#include <vector>
#include <algorithm>
#include "boost/bind.hpp"
class personal_info
{
std::string name_;
std::string surname_;
unsignedint age_;
public:
personal_info(const std::string& n,const std::string& s,unsignedint age):name_(n),surname_(s),age_(age){}
std::string name() const {return name_;}
std::string surname() const {return surname_;}
unsigned int age() const {return age_;}
}
;

void main()
{
std::vector<personal_info> vec;
vec.push_back(personal_info("Little","John",30));
vec.push_back(personal_info("Friar", "Tuck",50));
vec.push_back(personal_info("Robin", "Hood",40));
std::sort(vec.begin(),
vec.end(),
boost::bind(std::less<unsignedint>(),boost::bind(&personal_info::age,_1),boost::bind(&personal_info::age,_2))
);
std::sort(vec.begin(),
vec.end(),
boost::bind(std::less<std::string>(),boost::bind(&personal_info::surname,_1),boost::bind(&personal_info::surname,_2))
);
}

四 注意

1) 现在的类库最多可以支持9个参数。
2)在绑定一个成员函数时,bind 表达式的第一个参数必须是成员函数所在类的实例!理解这个规则的最容易的方法是,这个显式的参数将取

替隐式的 this ,被传递给所有的非静态成员函数。细心的读者将会留意到,实际上这意味着对于成员函数的绑定器来说,只能支持八个参数

,因为第一个要用于传递实际的对象。
3)当我们传递某种类型的实例给一个 bind 表达式时,它将被复制,除非我们显式地告诉 bind 不要复制它。要避免复制,我们必须告诉

bind 我们想传递引用而不是它所假定的传值。我们要用 boost::ref 和 boost::cref (分别用于引用和 const 引用)来做到这一点,它们也是

Boost.Bind 库的一部分。还有一种避免复制的方法;就是通过指针来传递参数而不是通过值来传递。
4) 通过 Boost.Bind, 你可以象使用非虚拟函数一样使用虚拟函数,即把它绑定到最先声明该成员函数为虚拟的基类的那个虚拟函数上。这

个绑定器就可以用于所有的派生类。如果你绑定到其它派生类,你就限制了可以使用这个绑定器的类。
5)bind还可以绑定成员变量。

bind并不是一个单独的类或函数,而是非常庞大的家族,依据绑定的参数个数和要绑定的调用对象类型,总共有十个不同的形式,但它们的名字都叫bind. 
bind接受的第一个参数必须是一个可调用对象f,包括函数,函数指针,函数对象和成员函数,之后bind接受最多9个参数,参数的数量必须与f的参数数量相等 
_1,_2这些一直可以到9,是占位符,必须在绑定表达式中提供函数要求的所有参数,无论是真实参数还是占位符均可以。占位符不可以超过函数参数数量。 
绑定普通函数:

#include<boost/bind.hpp>
#include<iostream>
using namespace std;
using namespace boost;

void fun(int a,int b){
        cout << a+b << endl;
}

int main()
{
        bind(fun,1,2)();//fun(1,2)
        bind(fun,_1,_2)(1,2);//fun(1,2)
        bind(fun,_2,_1)(1,2);//fun(2,1)
        bind(fun,_2,_2)(1,2);//fun(2,2)
        bind(fun,_1,3)(1);//fun(1,3)
}


3
3
3
4
4

绑定成员函数

#include<boost/bind.hpp>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace boost;
using namespace std;

struct point
{
    int x,y;
    point(int a=0,int b=0):x(a),y(b){}
    void print(){
        cout << "(" << x << "," << y << ")\n";
    }
    void setX(int a){
        cout << "setX:" << a << endl;
    }
    void setXY(int x,int y){
        cout << "setX:" << x << ",setY:" << y << endl;
    }
    void setXYZ(int x,int y,int z){
        cout << "setX:" << x << ",setY:" << y << "setZ:" << z << endl;
    }
};

int main()
{
    point p1,p2;
    bind(&point::setX,p1,_1)(10);
    bind(&point::setXY,p1,_1,_2)(10,20);
    bind(&point::setXYZ,p2,_1,_2,_3)(10,20,30);
    vector<point> v(10);
    //for_each的时候只需要_1就可以了
    for_each(v.begin(),v.end(),bind(&point::print,_1));
    for_each(v.begin(),v.end(),bind(&point::setX,_1,10));
    for_each(v.begin(),v.end(),bind(&point::setXY,_1,10,20));
    for_each(v.begin(),v.end(),bind(&point::setXYZ,_1,10,20,30));
}

setX:10
setX:10,setY:20
setX:10,setY:20setZ:30
(0,0)
(0,0)
(0,0)
(0,0)
(0,0)
(0,0)
(0,0)
(0,0)
(0,0)
(0,0)
setX:10
setX:10
setX:10
setX:10
setX:10
setX:10
setX:10
setX:10
setX:10
setX:10
setX:10,setY:20
setX:10,setY:20
setX:10,setY:20
setX:10,setY:20
setX:10,setY:20
setX:10,setY:20
setX:10,setY:20
setX:10,setY:20
setX:10,setY:20
setX:10,setY:20
setX:10,setY:20setZ:30
setX:10,setY:20setZ:30
setX:10,setY:20setZ:30
setX:10,setY:20setZ:30
setX:10,setY:20setZ:30
setX:10,setY:20setZ:30
setX:10,setY:20setZ:30
setX:10,setY:20setZ:30
setX:10,setY:20setZ:30
setX:10,setY:20setZ:30


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值