boost::bind 学习

 最近学习了太多与MacOS与Iphone相关的东西,因为不会有太多人有兴趣,学习的平台又是MacOS,不太喜欢MacOS下的输入法,所以写下来的东西少了很多。
    等我学习的东西慢慢的与平台无关的时候,可能可以写下来的东西又会慢慢多起来吧。。。。。不过我想早一批订阅我博客的人应该已经不会再看了,因为已经很少会有程序语言或者C++之类的信息,相关的东西应该都是关于计算机图形,游戏的。或者,早一批订阅我博客的人现在也已经毕业,工作了呢?
    对了,这次的主题是boost:bind。在历经了
boost::asio(1) 
boost::asio(2) 
boost::asio(3) 
boost::foreach 
boost::function 
boost::lambda 
boost::serialization(1) 
boost::serialization(2) 
boost::string_algo 
boost::thread 

之后,boost常用的很多都学会了,现在自己写点小东西,那是大胆的用大。。。。。。。呵呵,反正自己的东西,就当用来锻炼技术了。在学习boost::signal2的过程中发现自己其实对boost::bind这个将来要进C++标准的库了解还不够多,(在boost::functon中有所提及,也同时学了一点),所以抽了点时间,好好的学习了一下。

Purpose(目的)

原来文档中的purpose完全就是教程了,事实上,bind主要用于改造函数,比如,一个地方需要一个无参的函数,你只有一个以int为参数的函数,并且你知道此时int一直为1就可以了,你怎么办?传统方法,直接实现一个函数,然后以1调用以前的那个int为参数的函数。如下:

void  Fun1(int  i) {
    printf(" %d /n " , i);
}

void  FunWeNeed() {
    Fun1(1 );
}

int  main()
{
    FunWeNeed();
    

    return  0 ;
};

当然,这个例子太扯了,我们只需要直接用Fun1(1)调用就可以了,但是bind的目的就是如此,只不过现实中因为各种各样的原因,你的确需要改造函数。再比如下面的情况,你有一个原来写好的函数,接受一个以无参函数为参数,那么,你的Fun1就没有办法派上用场了,那么,传统上,怎么办?如下:

typedef   void  FunWeNeed_t(void );

void  CallFun( FunWeNeed_t f) {
    f();
}

void  Fun1(int  i) {
    printf(" %d /n " , i);
}

void  FunWeNeed() {
    Fun1(1 );
}

int  main()
{

//  CallFun(Fun1);          // this line can't compile 
    CallFun(FunWeNeed);

    return  0 ;
};

Ok,你不得不写新的函数以满足需求,因为你没有简单的办法改变一个函数的参数。事实上,假如你是STL流派的话,那么随着你使用标准库的算法的次数的增加,你会遇到越来越多上面描述的情况,到底很简单,C++是如此的类型安全的语言,它不会加上诸如参数过多就忽略后面参数的胡扯特性。那么,一个算法需要你传进来的是什么形式的函数(或者函数对象),那么你就的怎么做。
去看看,标准库中提供了一大堆多么扯的函数对象吧,less, more,,greater_equal,not1,not2,。。。。。。然后还给了你一堆compose1,compose2........最后附带最恶心的bind1st,bind2nd,事实上,这些东西如此之多,以至于我甚至懒的列举出来,但是事实上我们在项目中用到了多少?简而言之,None!一次也没有,甚至因为很多算法与此相关,我们连那些算法也不用!
为啥C++当年出现了那么多奇怪臃肿无用的设计?可能是,C++标准出现的那个年代,编程技术的发展也就到那个地步吧。。。。。。。。。在C/C++语言中,关于函数的抽象特别的少,原因很简单,因为函数指针太不好用了!(函数抽象也用,但是好像用的最多的是在C语言中无物可用时,不得已的而为之)

记得在哪看过一句话,技术再花哨也没有用,最重要的是足够简单,因为不够简单的技术就很难给人讲解,别人很难理解那么就很难应用。这些C++特性应该算是其中的一例了。
boost中的bind,function ,lambda 就是为此而生的。注意,在tr1中,你就已经可以使用bind和function特性了,这也很可能是将来的C++标准之一。现在boost中的lambda还不够成熟,语法很怪,限制很多,因为,毕竟,boost再强大,仅仅是库啊。。。。。。。。。匿名函数的功能完全值得用语言特性来实现!
上面那个很扯的例子,总的给个bind的解决方案吧。

#include <boost/bind.hpp> 
#include <boost/function.hpp> 

void  CallFun( boost::function<void (void )> f) {
    f();
}

void  Fun1(int  i) {
    printf(" %d /n " , i);
}

void  FunWeNeed() {
    Fun1(1 );
}

int  main()
{

    CallFun(boost::bind(Fun1, 1 ));         // this line can't compile 
    CallFun(FunWeNeed);

    return  0 ;
};
需要注意的是,此时不能再使用函数指针了,bind的天生合作伙伴是function,而function是支持函数指针的(如上例所示) 。目的将的很多了,下面看看用法吧(不是什么问题)。

普通函数

最有意思的是,你甚至能用bind来扩充原有函数的参数,见下例:

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

void  f(int  a, int  b)
{
    cout <<"Argument 1 is "  <<a <<endl;
}

void  g(int  a, int  b, int  c)
{
    cout <<"sum is "  <<a+b+c <<endl;
    cout <<"arg 1: "  <<a <<endl;
    cout <<"arg 2: "  <<b <<endl;
    cout <<"arg 3: "  <<c <<endl;
    cout <<"---------------------------"  <<endl;
}

int  main()
{

    function<void (int ,int )>  f1= bind(f, _2, _1);                 // 调整参数1,2的位置 
    f1(1 , 2 );

    function<void (int )> sum1 = bind(g, _1, _1, _1);        // 3个参数变1个 
    sum1(10 );

    function<void (int , int )> sum2 = bind(g, _2, _2, _2);       // 3个参数变2个,仅用一个 
    sum2(10 , 20 );

    function<void (int , int , int )> sum3 = bind(g, _3, _3, _3);      // 3个参数还是3个,但是仅用1个
    sum3(10 , 20 , 30 );

    function<void (int , int , int , int )> sum4 = bind(g, _4, _4, _4);     // 3个参数变4个,但是仅用1个 
    sum4(10 , 20 , 30 , 40 );

    return  0 ;
};

输出结果:

Argument 1 is 2
sum is 30
arg 1: 10
arg 2: 10
arg 3: 10
---------------------------
sum is 60
arg 1: 20
arg 2: 20
arg 3: 20
---------------------------
sum is 90
arg 1: 30
arg 2: 30
arg 3: 30
---------------------------
sum is 120
arg 1: 40
arg 2: 40
arg 3: 40
---------------------------

函数对象

注意用法中很重要的一条:通常情况下,生成的函数对象的 operator() 的返回类型必须显式指定(没有 typeof 操作符,返回类型无法推导)。(来自Boost文档)

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

struct  F
{
    int  operator ()(int  a, int  b) { return  a - b; }
    bool  operator ()(long  a, long  b) { return  a == b; }
};

int  main()
{
    F f;

    int  x = 104 ;

    function< int (int ) > fun1 = bind<int >(f, _1, _1);      // f(x, x), i.e. zero 

    cout <<fun1(1 );

    function< bool (long ) > fun2 = bind<bool >(f, _1, _1);       // f(x, x), i.e. zero 

    cout <<fun2(1 );

    return  0 ;
};

其他的也就很简单了。

成员指针

例子来源于boost文档。
#include <iostream> 
#include <boost/bind.hpp> 
#include <boost/function.hpp> 
#include <boost/smart_ptr.hpp> 
using  namespace  std;
using  namespace  boost;

struct  X
{
    void  f(int  a) {
        cout <<a <<endl;
    }
};

int  main()
{
    X x;

    shared_ptr<X> p(new  X);

    int  i = 1 ;

    bind(&X::f, ref(x), _1)(i);     // x.f(i) 
    bind(&X::f, &x, _1)(i);         //(&x)->f(i) 
    bind(&X::f, x, _1)(i);          // (internal copy of x).f(i) 
    bind(&X::f, p, _1)(i);          // (internal copy of p)->f(i) 

    return  0 ;
}

可见bind的强大,支持自己拷贝需要的对象,支持引用,甚至,支持智能指针。

最后一个例子,结合标准库容器及算法的例子,这才是展示bind的强大的地方。

还是来自于boost文档。
class  image;
class  animation
{
public :

    void  advance(int  ms);
    bool  inactive() const ;
    void  render(image & target) const ;
};

std::vector<animation> anims;

template <class  C, class  P> void  erase_if(C & c, P pred)
{
    c.erase(std::remove_if(c.begin(), c.end(), pred), c.end());
}

void  update(int  ms)
{
    std::for_each(anims.begin(), anims.end(), boost::bind(&animation::advance, _1, ms));
    erase_if(anims, boost::mem_fn(&animation::inactive));
}

void  render(image & target)
{
    std::for_each(anims.begin(), anims.end(), boost::bind(&animation::render, _1, boost::ref(target)));
}

例子展示了erase_if,for_each算法中使用bind的方法,当然,实际中,假如是你的游戏引擎中的update,render函数,碰到上述需求或者类似代码实现是很正常的,但是,你会放心的仅仅为了简化一些代码,然后将如此性能相关的位置,直接交给bind吗?

时间: 2024-07-29 02:15:39

boost::bind 学习的相关文章

boost库学习随记六:使用同步定时器、异步定时器、bind、成员函数回调处理、多线程的同步处理示例等

一.使用同步定时器 这个示例程序通过展示如何在一个定时器执行一个阻塞等待.       [cpp] view plaincopy   //makefile   #----------------------------------------------------------   #makefile helloworld测试用例   #   #   #   #   #-----------------------------------------------------------   gg

boost::bind的使用方法

bind - boost 头文件: boost/bind.hpp bind 是一组重载的函数模板. 用来向一个函数(或函数对象)绑定某些参数. bind的返回值是一个函数对象. 它的源文件太长了. 看不下去. 这里只记下它的用法: 9.1 对于普通函数 假如有函数 fun() 如下:  void fun(int x, int y) {   cout << x << ", " << y << endl;  } 现在我们看看怎么用 bind

关于boost::bind中fstream对象禁止拷贝的解决方法

fstream的拷贝构造函数是私有的,禁止fstream对象的拷贝. 比如,下面的程序编译出错,提示拷贝构造函数私有: #include<fstream> #include<iostream> #include<boost/thread/thread.hpp> using namespace std; void fun(ofstream &out) { std::cout<<"succeed!"<<endl; } in

boost::bind 与 boost::function 的使用方法例子

啥也不说,直接看代码: #include <boost/bind.hpp> #include <boost/function.hpp> #include <iostream> using namespace boost; using namespace std; int f(int a, int b) { return a + b; } int g(int a, int b, int c) { return a + b * c; } class Point { publ

Boost Thread学习笔记五

多线程编程中还有一个重要的概念:Thread Local Store(TLS,线程局部存储),在boost中,TLS也被称作TSS,Thread Specific Storage.boost::thread库为我们提供了一个接口简单的TLS的面向对象的封装,以下是tss类的接口定义: class tss{public:    tss(boost::function1<void, void*>* pcleanup);    void* get() const;    void set(void*

Boost Test学习总结(C++)

1.常用的C++单元测试框架 测试驱动开发(TDD)已经是一种非常流行的开发方式了,在Java和.Net中都提供了非常好的单元测试框架,最近研究C++下面的单元测试,发现其实在C++中还是有很多选择: CPPUnit:著名的XUnit系列产品之一,熟悉JUnit.NUnit的开发人员可以很快上手. CXXTest:需要进行预处理,需要安装Perl或Python. Boost Test:功能强大,提供了自动注册和手动注册两种方式,更重要的是来自千锤百炼的Boost库. Google Test:Go

Boost Thread学习笔记二

除了thread,boost::thread另一个重要组成部分是mutex,以及工作在mutex上的boost::mutex::scoped_lock.condition和barrier,这些都是为实现线程同步提供的. mutexboost提供的mutex有6种:boost::mutexboost::try_mutexboost::timed_mutexboost::recursive_mutexboost::recursive_try_mutexboost::recursive_timed_m

Boost Thread学习笔记三

下面先对condition_impl进行简要分析.condition_impl在其构造函数中会创建两个Semaphore(信号量):m_gate.m_queue,及一个Mutex(互斥体,跟boost::mutex类似,但boost::mutex是基于CriticalSection<临界区>的):m_mutex,其中:m_queue相当于当前所有等待线程的等待队列,构造函数中调用CreateSemaphore来创建Semaphore时,lMaximumCount参数被指定为(std::nume

boost uuid 学习笔记

#include <vector>#include <iostream>#include <boost/uuid/uuid.hpp>#include <boost/uuid/uuid_generators.hpp>#include <boost/uuid/uuid_io.hpp>using namespace boost::uuids;using namespace std;int main(){ //----------------------