热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Boost::bind使用详解

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

  在STL中,我们经常需要使用bind1st,bind2st函数绑定器和fun_ptr,mem_fun等函数适配器,这些函数绑定器和函数适配器使用起来比较麻烦,需要根据是全局函数还是类的成员函数,是一个参数还是多个参数等做出不同的选择,而且有些情况使用STL提供的不能满足要求,所以如果可以我们最好使用boost提供的bind,它提供了统一的接口,提供了更多的支持,比如说它增加了shared_ptr,虚函数,类成员的绑定。

2.bind的工作原理

  bind并不是一个单独的类或函数,而是非常庞大的家族,依据绑定的参数的个数和要绑定的调用对象的类型,总共有数十种不同的形式,编译器会根据具体的绑定代码制动确定要使用的正确的形式,bind的基本形式如下:

1 template<class R,class F> bind(F f);
2 template<class R,class F,class A1> bind(F f,A1 a1);
3 namespace
4 {
5 boost::arg<1> _1;
6 boost::arg<2> _2;
7 boost::arg<3> _3;
8 …..                                     //其他6个占位符
9 };
View Code

  bind接收的第一个参数必须是一个可调用的对象f,包括函数函数指针函数对象、和成员函数指针,之后bind最多接受9个参数参数数量必须与f的参数数量相等,这些参数被传递给f作为入参。 绑定完成后,bind返回一个函数对象,它内部保存了f的拷贝,具有operator()返回值类型自动推导f的返回类型。在发生调用时这个函数对象将把之前存储的参数转发给f完成调用。例如,有一个函数func,它的形式是:

1 func(a1,a2);

那么,他将等价于一个具有无参operator()的bind函数对象调用:

1 bind(func,a1,a2)();

  这是bind最简单的形式,bind表达式存储了func和a1、a2的拷贝,产生了一个临时函数对象。因为func接收两个参数,而a1和a2的拷贝传递给func完成真正的函数调用。

  bind的真正威力在于它的占位符,它们分别定义为_1,_2,_3,一直到 _9,位于一个匿名的名字空间。占位符可以取代bind参数的位置,在发生调用时接受真正的参数占位符的名字表示它在调用式中的,而在绑定的表达式中没有没有顺序的要求,_1不一定必须第一个出现,也不一定只出现一次,例如:

1 bind(func,_2,_1)(a1,a2);

  返回一个具有两个参数的函数对象,第一个参数将放在func的第二个位置,而第二个参数则放在第一个位置,调用时等价于:

1 func(a2,a1);
3.常用的函数对象工具

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

4.bind与其他函数对象工具区别

4.1 区别与mem_fun和fun_ptr

 1 #include 
 2 #include 
 3 #include <string>
 4 #include "boost/bind.hpp"
 5 class some_class 
 6 {
 7 public:      
 8     void print_string(const std::string& s) const
 9     {    
10         std::cout <'\n'; 
11     }
12     void print_classname()
13     {
14         std::cout <<"some_class" << std::endl;
15     }
16 };
17 void print_string(const std::string s) 
18 {  std::cout <'\n';
19 }
20 void print_functionname()
21 {
22     std::cout <<"Print_functionname" <<std::endl;
23 }
24 int main() 
25 {  
26     std::ptr_fun(&print_string)("hello1");
27     //std::ptr_fun(&print_functionname);
28     some_class sc0;
29     std::mem_fun_ref(&some_class::print_classname)(sc0);
30     std::mem_fun_ref<void,some_class>(&some_class::print_classname)(sc0);
31     //std::mem_fun1_ref(&some_class::print_string)(sc0,"hello2");
32 
33     (boost::bind(&print_string,_1))("Hello func!");  
34     boost::bind(&print_functionname);
35     some_class sc;  
36     (boost::bind(&some_class::print_classname,_1)(sc));
37     (boost::bind(&some_class::print_string,_1,_2))(sc,"Hello member!");
38 }
View Code

4.2 区别与bind1st和bind2st

 1 #include 
 2 #include 
 3 #include <string>
 4 #include 
 5 #include 
 6 #include "boost/bind.hpp"
 7 void main()
 8 {
 9     std::vector<int> ints;
10     ints.push_back(7);
11     ints.push_back(4);
12     ints.push_back(12);
13     ints.push_back(10);
14     int count=std::count_if(ints.begin(),  
15         ints.end(), 
16         boost::bind(std::logical_and<bool>(),boost::bind(std::greater<int>(),_1,5),boost::bind(std::less_equal<int>(),_1,10))
17         );
18     std::cout <'\n';
19     std::vector<int>::iterator int_it=std::find_if(ints.begin(),  
20         ints.end(),  
21         boost::bind(std::logical_and<bool>(),boost::bind(std::greater<int>(),_1,5),boost::bind(std::less_equal<int>(),_1,10))
22         );
23     if (int_it!=ints.end()) 
24     {  std::cout <<*int_it <<'\n';}
25 
26 }
View Code

4.3 区别传ref和传instance

 1 // bind instance or reference
 2 #include 
 3 #include 
 4 #include <string>
 5 #include 
 6 #include 
 7 #include "boost/bind.hpp"
 8 class tracer 
 9 {
10 public: 
11     tracer() {    std::cout <<"tracer::tracer()\n";  } 
12     tracer(const tracer& other) {    std::cout <<"tracer::tracer(const tracer& other)\n";  } 
13     tracer& operator=(const tracer& other)
14     {    std::cout <<"tracer& tracer::operator=(const tracer& other)\n";    return *this;  } 
15     ~tracer() {    std::cout <<"tracer::~tracer()\n"; 
16     } 
17     void print(const std::string& s) const
18     {    std::cout <'\n';  }
19 };
20 
21 void main()
22 {
23     tracer t;
24     boost::bind(&tracer::print,t,_1)(std::string("I'm called on a copy of t\n"));
25     tracer t1;
26     boost::bind(&tracer::print,boost::ref(t1),_1)(  std::string("I'm called directly on t\n"));
27 
28 }
View Code
5.bind的应用场景

5.1 绑定普通函数

  bind可以绑定普通函数,包括函数函数指针,假设我么有如下的函数定义:

1 int f(int a,int b){return a+b;}   //二元函数
2 int g(int a,int b,int c) {return a+b+c;} //三元函数
3 typedef int (*f_type)(int,int);      //函数指针定义
4 typedef int (*g_type)(int,int,int); //函数指针定义
View Code

  那么,bind(f,1,2) 将返回一个无参调用函数对象,等价于f(1,2),bind(q,1,2,3)同样返回一个无参调用的函数对象,等价于 g(1,2,3)。这两个绑定表达式没有使用占位符,而是给出了全部的具体参数,代码:

1 cout<1,2)()<<endl;
2 cout<1,2,3)()< 

  相当于:

1 cout<1,2)<<endl;
2 cout<1,2,3)< 

  使用占位符bind可以有更多的变化,这才是它真正应该做的工作,下面列出了一些占位符的用法:

1 bind(f,_1,9)(x);  //f(x,9),相当于bind2nd(f,9)
2 bind(f,_1,_2)(x,y); //f(x,y)
3 bind(f,_2,_1)(x,y); //f(y,x)
4 bind(f,_1,_1)(x,y); //f(x,x),y参数被忽略
5 bind(g,_1,8,_2)(x,y) //g(x,8,y)
6 bind(g,_3,_2_2)(x,y,z) //g(z,y,y),x参数被忽略
View Code

  注意:必须绑定表达式中提供函数要求所有参数,无论是真实参数还是占位符均可以占位符可以出现也可以不出现,出现的顺序数量没有限定,但不能使用超过函数参数数量占位符,比如在绑定f是不能用_3,在绑定g时不能使用_4,也不能写bind(f,_1,_2,_2),这样的形式会导致编译错误。bind完全可以代替标准库中的bind1st和bind2nd,使用bind(f,N,_1)和bind(f,_1,N)。要注意的是它们均使用了一个占位符,bind1st把第一个参数用固定值代替,bind2nd把第二个参数用固定值代替。bind也可以绑定函数指针,用法相同,例如:

1 f_type pf = f;
2 g_type pg = g;
3 int x =1,y=2,z=3;
4 cout<9)(x)<//(*pf(x,9))
5 cout<//(*pg)(z,y,y)
View Code

5.2 bind绑定成员函数

  类的成员函数不同于普通的函数,因为成员函数指针不能直接调用operator(),它必须绑定到一个对象指针,然后才能得到this指针进而调用成员函数。因此bind需要 “牺牲”一个占位符,要求提供一个类的实例引用或者指针,通过对象作为第一个参数来调用成员函数,即:

1 bind(&X::func,x,_1,_2,…)

  这意味着使用成员函数时只能最多绑定8个参数。例如,有一个类demo

1 struct demo
2 {
3     int f(int a,int b){return a+b;}
4 };

推荐阅读
  • DFS基本概念步骤优缺点典型例题递推基本概念直接或者间接调用自身的算法称为递归算法一般数据n ... [详细]
  • 题目链接:杭电多校7-VirtualJudgevjudge上题目显示的有问题,我下面附上官方题目:样例输入:32201 ... [详细]
  • [USACO 2006 November Gold] 玉米地Corn Fields
    题目描述  FarmerJohn新买了一块长方形的牧场,这块牧场被划分成M行N列(1<M<12;1<N<12),每一格都是一块正方形的土地。FJ打 ... [详细]
  • 水题。。main.cppPATA1121CreatedbyPhoenixon2018224.Copyright©2018年Phoenix.Allrightsreserve ... [详细]
  • 题目描述输入整型数组和排序标识,对其元素按照升序或降序进行排序(一组测试用例可能会有多组数据)本题有多组输入,请使用whil ... [详细]
  • PIMPL 是 C++ 中的一个编程技巧,意思为指向实现的指针。具体操作是把类的实现细节放到一个单独的类中,并用一个指针进行访问 ... [详细]
  • 题意给出一个长度为n的序列,有一些位置可以放任意的数,问最长上升序列的长度。n ... [详细]
  • 问题描述  编写一个程序,输入一个1000以内的正整数,然后把这个整数的每一位数字都分离出来,并逐一地显示。  输入格式:输 ... [详细]
  • [二分图]JZOJ 4612 游戏
    DescriptionInputOutputSampleInput44#****#****#*xxx#SampleOutput5DataConstraint分析非常眼熟࿰ ... [详细]
  • Java的核心库提供了大量的现成的类供我们使用。本节我们介绍几个常用的工具类。Math顾名思义,Math类就是用来进行数学计算的,它提供了大量的静态 ... [详细]
  • 开发笔记:sql盲注之报错注入(附自动化脚本)
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了sql盲注之报错注入(附自动化脚本)相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 在这一期的SendMessage函数应用中,我将向大家介绍如何利用消息函数来扩展树型列表(TreeView)控件的功能相信对于树型列表控件大家十分的熟悉, ... [详细]
  • 使用RSACryptoServiceProvider进行公钥加密我已经在CodeProject上发表了一篇文章,解释了如何使用RSA提供程序进行加密和解密:RSA私钥加密虽然200 ... [详细]
  • 下面是一个用openssl实现获取https网页内容的demo,整个流程比较简单,主要封装的API如下staticinthttps_init(http ... [详细]
  • 对于输入的每个字符串,查找其中的最大字母,在该字母后面插入字符串“(max)”。Input输入数据包括多个测试实例,每个实例由一行长度 ... [详细]
author-avatar
奋斗中DU_536
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有