c++ 之 【boost::bind使用】
发布日期:2021-11-03 21:19:20
浏览次数:8
分类:技术文章
本文共 3487 字,大约阅读时间需要 11 分钟。
bind - boost
头文件: boost/bind.hpp
bind 是一组重载的函数模板。用来向一个函数(或函数对象)绑定某些参数.。bind的返回值是一个函数对象。
STL和Boost中的算法和函数大量使用了函数对象作为判断式或谓词参数,而这些参数都是传值语义,算法或函数在内部保存函数对象的拷贝并使用,一般情况下传值语义都是可行的,但也有很多特殊情况,作为参数的函数对象拷贝代价过高(具有复杂的内部状态),或者不希望拷贝对象(内部状态不应该被改变),甚至拷贝是不可行的(noncopyable、单件)。boost::ref应用代理模式,引入对象引用的包装器概念解决了这个问题。例boost::bind(&my_func, boost::ref(x), _1)
1.对于普通函数
假如有函数 fun() 如下:
void fun(int x, int y) { cout << x << ", " << y << endl; } 现在我们看看怎么用 bind 向其绑定参数. 对于像 fun 这样的普通函数. 若fun 有n个参数. 则 bind 需要 n+1 个参数: 原始函数的地址 以及 n个要绑定的参数.1.1 第 1种用法:
向原始函数 fun 绑定所有的参数
boost::bind(&fun, 3, 4) // bind的实参表依次为: 要绑定的函数的地址, 绑定到fun的第一个参数值, 第二个参数值... // fun有多少个参数, 这里就要提供多少个. 表示将 3 和 4 作为参数绑定到 fun 函数. 因为绑定了所有的参数. 现在我们调用bind所返回的函数对象: boost::bind(&fun, 3, 4)( ); //无参数. 就会输出 3, 41.2 第 2种用法:
向原始函数 fun 绑定一部分参数
boost::bind(&fun, 3, _1) // bind的实参表依次还是: 要绑定的函数的地址, 要绑定到fun的第一个参数值, 然后注意 // 因为我们不打算向fun绑定第2个参数(即我们希望在调用返回的Functor时再指定这个参数的值) // 所以这里使用 _1 来占位. 这里的 _1 代表该新函数对象被调用时. 实参表的第1个参数. // 同理下边还会用到 _2 _3 这样的占位符. 这里只为fun绑定了第一个参数3. 所以在调用bind返回的函数对象时. 需要: boost::bind(&fun, 3, _1)(4); //这个4 会代替 _1 占位符. 输出 3, 4 同理 boost::bind(&fun, _1, 3)(4); 输出 4, 31.3 第3种用法:
不向 fun 绑定任何参数
boost::bind(&fun, _1, _2) // _1 _2 都是占位符. 上边已经说过了. 所以它就是 将新函数对象在调用时的实参表的第1个参数和第2个参数 绑定到fun函数. boost::bind(&fun, _1, _2)(3, 4); // 3将代替_1占位符, 4将代替_2占位符. 输出 3, 4 同理 boost::bind(&fun, _2, _1)(3, 4); // 3将代替_1占位符, 4将代替_2占位符. 会输出 4, 3 同理 boost::bind(&fun, _1, _1)(3); // 3将代替_1占位符 会输出 3, 3对于普通函数就这些. 对于函数对象. 如:
struct Func { void operator()(int x) { cout << x << endl; } } f; 绑定的时候可能要指出返回值的类型: boost::bind<void>(f, 3)(); //指出返回值的类型 void
2. 对于非静态成员函数
假如有:
struct A { void func(int x, int y) { cout << x << "," << y << endl; } }; A a; A* pa = new A; //指针 boost::shared_ptr<A> ptr_a(pa); //智能指针. 现在要向像 A::func 这样的非静态成员函数绑定. 若A::func有n个参数, 则 bind 要有 n+2 个参数: 指向成员函数fun的指针, 绑定到this的对象, n个参数. 如: boost::bind(&A::func, a, 3, 4)(); //输出 3, 4 boost::bind(&A::func, pa, 3, 4)(); //输出 3, 4 boost::bind(&A::func, ptr_a, 3, 4)();//输出 3, 4 同样可以用 _1 这样的占位符. 如: boost::bind(&A::func, _1, 3, 4)(ptr_a);//输出 3, 4可以看出. 不论传递给bind 的第2个参数是 对象. 对象指针. 还是智能指针. bind函数都能够正常工作.
但是有两种情况是特殊的,即: 1、该对象不可进行拷贝构造函数。 2、该对象不可随意被析构。 发现这个问题是在我编写单件模式时的遇见的,当时发现我的单件对象在bind中被析构了一次,这很不寻常,为什么bind会调用第一个参数的析构呢?跟踪进了boost的源码才发现,原来所有的参数都会被拷贝一遍,然后析构一遍,这样一来,我们传递参数的时候就会有一些小麻烦了,首先必须保证参数能够被拷贝而不影响逻辑和数据一致性,其次,参数能够被析构而不影响逻辑和数据一致性。单件是全局性质的数据,所以绝对不可以析构,那么这种情况的话,我们只好传递单件对象的地址,而不能传递值或引用。
3. bind嵌套
有个类如下. 记录人的信息:
class Personal_info { string name_; int age_; public: int get_age(); string name(); };vector<Personal_info> vec;
... 现在要对 vec 排序. 可以用 bind 函数做一个比较谓词 std::sort( vec.begin(), vec.end(), boost::bind( std::less<int>(), boost::bind(&personal_info::age,_1), //_1 占位符是 sort 中调用比较函数时的第一个参数. boost::bind(&personal_info::age,_2))); //_2 占位符是 sort 中调用比较函数时的第二个参数.
4. 函数组合
假如有:
vector<int> ints; ... 想用 std::count_if() 来求ints中有多少是 >5 且 <=10 的. 这在常规代码中通常就要写一个函数来实现这个谓词: if (i>5 && i<=10) ... 现在用 bind则可以: 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)));
5. 绑定到成员变量
有:
map<int, string> my_map; my_map[0]="Boost";my_map[1]="Bind"; 现在要输出所有元素的 second 成员. 也就是输出这些字符串. 其中的打印函数如下: void print_string(const string& s) { std::cout << s << '\n'; } 则可以: for_each( my_map.begin(), my_map.end(), boost::bind( &print_string, boost::bind(&std::map<int,std::string>::value_type::second,_1) ) );
注意事项:
为什么与的 boost::bind内参数不一样。因为前者绑定的是类的成员函数,后者绑定的是全局函数,而bind在用于非静态成员函数时,需要多一个输入参数(对象指针),以说明是哪个对象,因此其参数数量为1+1+n。
转载地址:https://blog.csdn.net/wjydym/article/details/92214349 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
第一次来,支持一个
[***.219.124.196]2024年03月24日 05时46分55秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
python入门之基础语法第四关输入输出答案_Python基本语法入门,基础
2019-04-21
mysql在存储过程仍_mysql存储过程
2019-04-21
失败的人生图片_早安励志经典语录精辟的一句话人生感悟
2019-04-21
如何设画面大小_如何设计旅游类项目?分享3种设计思路
2019-04-21
从右边开始放_停路边,被人恶意放钉子,爆胎,报警无果,要我找监控
2019-04-21
读写测试_UFS 3.0读写测试数据曝光:秒杀UFS 2.1和eMMC
2019-04-21
注册小程序要多少钱_开发一个微信小程序商城要多少钱?
2019-04-21
mysql 实现id自增序列_MySQL分表自增ID解决方案
2019-04-21
catti二级笔译综合能力真题_CATTI韩语二级口译真题及考场回忆版
2019-04-21
攻防世界 适合做桌面_世界杯大冷门,双方实力悬殊,德国队为何输给了韩国队...
2019-04-21
可涂抹什么让指纹加深_手机镀膜是什么?液体玻璃手机镀膜和膜结手机纳米防护的区别...
2019-04-21
node静态服务器优缺点_Node —— BFF
2019-04-21
新风系统风速推荐表_PE管还是PVC管?现场评测新风系统两种管道对比
2019-04-21
华为社招嵌入式软件面试_嵌入式软件面试那点事
2019-04-21
心电图多少为正常范围_一个人的正常尿酸是多少,不管体重多少,不超过这个范围都算正常...
2019-04-21
用流密码实现加密java语言_使用java的流密码
2019-04-21