news 2026/10/23 1:01:36

【c++】C++:boost::bind的一些用法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【c++】C++:boost::bind的一些用法

没有对C++了解特别深入吧,还是对有些特性用法之类的不是很熟悉,阅读代码的时候还是碰到很多不明白。
下面是LZ读到的一句代码

boost::function<const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr &> f = boost::bind(&MainLoop::onNewCloud, this, _1);

boost::bind的用法

目的
boost :: bind是标准函数std :: bind1st和std :: bind2nd的泛化。 它支持任意函数对象,函数,函数指针和成员函数指针,并且能够将任何参数绑定到特定值或将输入参数路由到任意位置。 bind对函数对象没有任何要求; 特别地,它不需要result_type,first_argument_type和second_argument_type标准typedef。

通过函数或者函数指针使用bind

int f(int a, int b) { return a+b; } int g(int a, int b, int c) { return a+b+c; }

bind(f, 1, 2)会产生一个零元函数,它不接受参数并且返回f(1, 2)。类似的,bind(g, 1, 2, 3)( )等同于g(1, 2, 3)。

可以选择性地绑定一些参数。 bind(f,_1,5)(x)等价于f(x,5); 这里_1是一个占位符参数,意思是“用第一个输入参数替换”。

为了比较,这里是与标准库原语相同的操作:

std::bind2nd(std::ptr_fun(f), 5)(x);

bind也包含std :: bind1st的功能:

std::bind1st(std::ptr_fun(f), 5)(x); //f(5, x) bind(f, 5, _1)(x);//f(5, x)

bind可以处理具有两个以上参数的函数,其参数替换机制更为通用:

bind(f, _2,_1)(x, y); //f(y, x) bind(g, _1, 9, _1)(x); //g(x, 9, x) bind(g, _3, _3, _3)(x, y, z); //g(z, z, z) bind(g, _1, _1, _1)(x, y, z); //g(x, x, x)

请注意,在最后一个示例中,由bind(g,_1,_1,_1)生成的函数对象不包含超出第一个参数的引用,但仍可以使用多个参数。 任何额外的参数被默认忽略,就像第一个和第二个参数在第三个例子中被忽略。

绑定的参数被返回的函数对象复制并保存在内部。 例如,在以下代码中:

int i = 5; bind(f, i, _1);

i的值的副本存储在函数对象中。 boost :: ref和boost :: cref可用于使函数对象存储对对象的引用,而不是副本:

int i = 5; bind(f, ref(i), _1); bind(f, cref(i), _1);

通过函数对象使用bind
绑定不限于功能; 它接受任意函数对象。 在一般情况下,必须明确指定生成的函数对象的operator()的返回类型(不使用typeof运算符,不能推断返回类型):

struct F { int operator()(int a, int b){return a-b;} bool operator()(long a, long b){return a == b;} }; F f; int x = 104; bind<int>(f, _1, _1)(x); //f(x, x), i.e. zero

一些编译器遇到bind R(f,…)语法时遇到麻烦。 由于可移植性原因,支持表达上述的替代方法:

boost::bind(boost::type<int>(), f, _1, _1)(x);

但请注意,备用语法仅作为解决方法提供。 它不是界面的一部分。

当函数对象公开一个名为result_type的嵌套类型时,可以省略显式返回类型:

int x = 8; bind(std::less<int>(), _1, 9)(x); //x<9

[注意:省略返回类型的能力在所有编译器上都不可用]

默认情况下,bind将提供所提供的函数对象的副本。 boost :: ref和boost :: cref可用于使其存储对函数对象的引用,而不是副本。 当函数对象不可复制,复制昂贵或包含状态时,这可能很有用; 当然,在这种情况下,程序员期望确保功能对象在使用时不被销毁。

struct F2 { int s; typedef void result_type; void operator()(int x){ s+= x;} }; F2 f2 = {0}; int a[] = {1, 2, 3 }; std::for_each(a, a+3, bind(ref(f2), _1)); assert(f2.s == 6);

上面代码的目的是把a中的每个元素相加,求和结果保存到结构体f2.s中。

通过指向成员的指针使用bind

指向成员函数的指针和数据成员的指针不是函数对象,因为它们不支持operator()。 为方便起见,绑定接受成员指针作为其第一个参数,并且行为就好像已经使用boost :: mem_fn将成员指针转换为函数对象。 换句话说,表达为

bind(&X::f, args)

等价于

bind<R>(men_fn(&X::f), args)

其中R是X :: f(用于成员函数)的返回类型或成员的类型(对于数据成员)。

[注意:mem_fn创建能够接受指向对象的指针,引用或智能指针作为其第一个参数的函数对象; 有关其他信息,请参阅mem_fn文档。]

举例如下:

struct X { bool f(int a); }; X x; shared_ptr<X>p(new X); int i = 5; 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)

最后两个例子很有趣,因为它们产生“自包含”功能对象。 bind(&X :: f,x,_1)存储x的副本。 bind(&X :: f,p,_1)存储p的副本,由于p是一个boost :: shared_ptr,函数对象保留对其X实例的引用,并且即使p超出范围也将保持有效, 是reset()。

对于函数组合使用嵌套binds(感觉这个翻译好奇怪!)
传递给绑定的一些参数可能是嵌套绑定表达式本身:

bind(f, bind(g, _1))(x); //f(g(x))

内部绑定表达式在调用函数对象之前以非特定顺序进行外部绑定之前的计算; 当外部绑定被评估时,评估结果将被替换为它们的位置。 在上面的例子中,当使用参数列表(x)调用函数对象时,首先评估bind(g,_1)(x),得到g(x),然后bind(f,g(x)) x),得到最终结果f(g(x))。

绑定的这个特征可以用来执行功能组合。 有关示例演示如何使用bind实现与Boost.Compose类似的功能的示例,请参见bind_as_compose.cpp。

请注意,第一个参数 - 绑定函数对象 - 不被评估,即使它是由bind或占位符参数生成的函数对象,因此下面的示例不能按预期方式工作:

typedef void (*pf)(int); std::vector<pf> v; std::for_each(v.begin(), v.end(), bind(_1, 5));

可以通过将其第一个参数作为函数对象应用到其参数列表的其余部分的帮助函数对象apply来实现所需的效果。 为方便起见,apply.hpp头文件中提供了apply的实现。 以前的例子的修改版本如下所示:

typedef void(*pf)(int) std::vector<pf> v; std::for_each(v.begin(), v.end(), bind(apply<void>(), _1, 5));

虽然第一个参数是,默认情况下不进行评估,但所有其他参数都是。 有时候,有必要在第一个之后评估参数,即使它们是嵌套的绑定子表达式。 这可以通过另一个函数对象的帮助来实现,保护,掩饰类型,以便绑定不能识别和评估它。 被调用时,保护简单地将参数列表转发到其他函数对象。

头文件protect.hpp包含一个保护的实现。 为了保护绑定函数对象免于评估,请使用protect(bind(f,…))。

重载操作符(new in Boost1.33)
为方便起见,通过绑定重载逻辑非运算符产生的函数对象! 和关系和逻辑运算符==,!=,<,<=,>,> =,&&,||。

!bind(f,…)等价于bind(logical_not(),bind(f,…)),其中logical_not是一个函数对象,它接受一个参数x并返回!x。

bind(f,…)op x,其中op是关系或逻辑运算符,相当于bind(relation(),bind(f,…),x),其中,关系是一个函数对象,需要两个 参数a和b并返回一个操作b。

这在实践中意味着你可以方便地否定绑定的结果:

std::remove_if(first, last, !bind(&X::visible, _1)); //remove invisible objects

并将绑定的结果与值进行比较:

std::find_if(first, last, bind(&X::name, _1) == "Peter"); std::find_if(first, last, bind(&X::name, _1) == "Peter" || bind(&X::name, _1) == "Paul");

针对占位符:

bind(&X::name, _1) == _2

或者针对另外一个占位符:

std::sort(first, last, bind(&X::name, _1)< bind(&X::name, _2)); //sort by name

参考地址:
http://www.boost.org/doc/libs/1_65_1/libs/bind/doc/html/bind.html#bind.purpose.using_bind_with_functions_and_fu

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/23 1:01:20

【android】Application.mk的文件梳理

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/22 23:59:19

SSRF服务端请求伪造:原理、利用与防御实践

先说一个我自己的经历。某次线上排查&#xff0c;发现一台业务服务器在半夜不断向内网发起非常规的请求&#xff0c;抓包一看&#xff0c;目标端口从 3306 扫到 6379&#xff0c;再扫到 11211。顺着调用链往上追&#xff0c;问题落在了我们自己做的一个“URL预览”功能上——前…

作者头像 李华
网站建设 2026/10/22 23:56:32

SQL注入原理与防御实战:从数据库安全到参数化查询的完整指南

1. SQL注入到底是什么&#xff1a;从一道“不该通过”的登录说起聊SQL注入之前&#xff0c;先讲一个我早年做项目时遇到的真实案例。某公司内部系统上线没多久&#xff0c;运维反馈后台登录接口响应偶尔很慢&#xff0c;偶尔又很快&#xff0c;而且数据库负载波动明显。一开始怀…

作者头像 李华
网站建设 2026/10/22 23:49:47

ELM极限学习机原理及MATLAB回归预测实现详解

做回归预测&#xff0c;我最早接触的是BP神经网络。那会儿为了一个隐含层节点数反复试&#xff0c;梯度下降又慢&#xff0c;动不动就陷进局部最优&#xff0c;调参调到怀疑人生。后来在一次实际任务里遇到极限学习机&#xff0c;也就是ELM&#xff0c;我第一反应是&#xff1a…

作者头像 李华
网站建设 2026/10/22 23:44:24

Spring Boot测试实战:JUnit 5集成与测试切片技术详解

Spring测试这块&#xff0c;我一直觉得是被低估的宝藏。标题里两个关键词——JUnit 5集成与测试切片技术——前者解决“测试怎么写、怎么跑”的问题&#xff0c;后者解决“测试跑得慢、依赖重”的问题。很多团队项目跑一遍全量测试要十几分钟&#xff0c;一大半时间都耗在等测试…

作者头像 李华
网站建设 2026/10/22 23:43:08

.NET桌面应用自动更新方案详解:ClickOnce、Velopack、MSIX与自研选型指南

做前端 Web 的同事可能很难理解&#xff0c;为什么桌面端一个“检查更新”的按钮做起来能折磨人这么久。但凡是发过几个 .NET 桌面应用的人&#xff0c;基本都体会过这种状态&#xff1a;修完 bug 兴冲冲打好包传给用户&#xff0c;第二天用户还是用着老版本&#xff0c;然后拿…

作者头像 李华