使用BOOST BIND库提高C++程序性能(一)

2014-11-24 11:28:56 · 作者: · 浏览: 0

  • By Bj rn Karlsson
  • Aug 26, 2005

    翻译:Boost.Bind的用法

    Boost.Bind为函数和函数对象,值语义和指针提供语义了一致的语法。我们首先通过一些简单的例子来看看它的基本用法,之后我们会延伸到嵌套绑定以实现功能组合。理解bind用法的一个关键是理解占位符(placeholder)的概念。占位符表示该参数将在函数对象里面提供。Boost.Bind提供多达9个这样的参数——_1, _2, _3, _4, _5,_6,_7,_8, _9。你可以在想要加入参数的地方使用它们。在第一个示例程序中,我们定义一个函数“nine_arguments”,之后用bind表达式调用它。

    #include 
        
         
    #include boost/bind.hpp
    
    void nine_arguments(
      int i1,int i2,int i3,int i4,
        int i5,int i6,int i7,int i8, int i9) {
        std::cout << i1 << i2 << i3 << i4 << i5
          << i6 << i7 << i8 << i9 << '
    ';
    }
    
    int main() {
      int i1=1,i2=2,i3=3,i4=4,i5=5,i6=6,i7=7,i8=8,i9=9;
      (boost::bind(&nine_arguments,_9,_2,_1,_6,_3,_8,_4,_5,_7))
        (i1,i2,i3,i4,i5,i6,i7,i8,i9);
    }
        

    在这个程序中,你可以创建临时的匿名绑定器并且立即传参调用。如你所见,占位符的顺序是在本例中是混乱的,这使得参数的顺序也被打乱。另外,占位符可以在表达式中重复使用。示例程序1的输出是:

    921638457

    占位符的序数与参数的位置是对应的,也就是说,_1被换为第一个参数,_2被换为第二个参数,以此类推。

    原创:编程实验

    #include 
        
         
    #include 
         
           void PlaceholderTest(int a, int b, int c) { std::cout << a << b << c << std::endl; } int main() { int a = 1, b = 2, c = 3; //(boost::bind(&PlaceholderTest, _1, _2))(a, b); //error //(boost::bind(&PlaceholderTest, _1, _2, _1, _3))(a, b, c); //error //(boost::bind(&PlaceholderTest, _1, _2, _3))(a, b); //error (boost::bind(&PlaceholderTest, _1, _2, _1))(a, b); //OK,output:121 (boost::bind(&PlaceholderTest, 99, _2, _1))(a, b) //OK,output:9921 } 
         
        

    总结:

    1、参数占位符数量与函数形参数量必须一致

    2、占位符的替代值可以少于占位符数量

    3、占位符和实参可以混合使用

    翻译:调用成员函数(1)

    我们看看如何使用bind调用类的成员函数。首先我们也从一个可以由标准库完成的操作开始,这样方便我们对比标准库调用和Boost.Bind调用。当我们在标准库容器类类型中存储元素时,通常需要对部分或所有元素调用成员函数。通常的实现方法是,将这些操作可以放在一个循环中。但是现在有更好的解决办法。观察如下的简单类——status。我们之后将用它来展示Boost.Bind的简单易用和强大之处。

    class status {
    	std::string name_;
    	bool ok_;
    public:
    	status(const std::string& name):name_(name),ok_(true) {}
    
    	void break_it() {
    		ok_=false;
    	}
    
    	bool is_broken() const {
    		return ok_;
    	}
    
    	void report() const {
    		std::cout << name_ <<  is  <<
    			(ok_   working nominally:terribly broken) << '
    ';
    	}
    };

    如果我们将这个类的实例储存在vector中,当我们需要调用成员函数report时,大概要遵循以下步骤

    std::vector
        
          statuses;
    statuses.push_back(status(status 1));
    statuses.push_back(status(status 2));
    statuses.push_back(status(status 3));
    statuses.push_back(status(status 4));
    
    statuses[1].break_it();
    statuses[2].break_it();
    
    for (std::vector
         
          ::iterator it=statuses.begin(); it!=statuses.end();++it) { it->report(); }
         
        

    for循环能够正确完成操作,但是它冗长、低效(每次都要检查statuses.end()),还不如使用标准库中专为这种操作设计的for_each算法来的清楚。为了使用for_each替代for循环,我们需要为vector元素调用成员函数report配置一个适配器。在这个实例中,由于元素是值存储的,我们需要的是mem_fun_ref适配器:

    std::for_each(
    	statuses.begin(),
    	statuses.end(),
    	std::mem_fun_ref(&status::report));

    这是一种更好的办法——它是如此简洁,不会对代码的作用产生任何迷惑和误解。Boost.Bind中的等效代码如下:

    std::for_each(
    	statuses.begin(),
    	statuses.end(),
    	boost::bind(&status::report,_1));

    bind版本仍然清晰明了。这是我们第一次真正使用上面提及的Bind库占位符,它向编译器和代码阅读者传递了这样一个信息,_1将在调用绑定器的函数中被实参替换。尽管这段代码长度减少了,但在本例中,它与使用标准库mem_fun_ref几乎没有差别。

    原创:编程实验

    #include 
        
         
    #include 
         
           #include 
          
            #include 
           
             #include 
            
              class Status { public: Status(const std::string &name) : name_(name), ok_(true){} void BreakIt() { ok_ = false; } bool IsBroken() const { return ok_; } void Report() const { std::cout << name_ << is << (ok_   ok : broken) << std::endl; } private: std::string name_; bool ok_; }; int main() { std::vector
             
               v_status; v_status.push_back(Status(status 1)); v_status.push_back(Status(status 2)); v_status.push_back(Status(status 3)); v_status.push_back(Status(status 4)); v_status[1].BreakIt(); v_status[2].BreakIt(); std::cout << use or: << std::endl; for (std::vector
              
               ::iterator it = v_status.begin(); it < v_status.end(); it++) { it->Report(); } std::cout << use or_each, mem_fun_ref: << std::endl; std::for_each(v_status.begin(), v_status.end(), std::mem_fun_ref(&Status::Report)); std::cout << use or_each, bind: << std::endl; //std::for_each(v_status.begin(), v_status.end(), boost::bind(&Status::Report)); //error std::for_each(v_status.begin(), v_status.end(), boost::bind(&Status::Report, _1)); }
              
             
            
           
          
         
        

    总结:

    bind成员函数最大的不同是,必须指明调用该函数的实例对象,代码中用“_1”表示。

    翻译:调用成员函数(2)

    下面,我们稍微改造一下vector容器,让它装入指针而不是值:

    std::vector
        
          p_statuses;
    p_statuses.push_back(new status(status 1));
    p_statuses.push_back(new status(status 2));
    p_statuses.push_back(new status(status 3));
    p_statuses.push_back(new status(status 4));
    
    p_statuses[1]->break_it();
    p_statuses[2]->break_it();
        

    我们仍然可以用两种标准库,但是我们不能用mem_fun_ref,而是用mem_fun适配器,虽然它的名字听起来有点儿混淆,完成操作还是没问题的。

    std::for_each(
    	p_statuses.begin(),
    	p_statuses.end(),
    	std::mem_fun(&status::report));

    注意到,这段代