C++ ROS与boost:bind()使用详解
Amelie_xiao 人气:01. boost::bind
boost::bind
是标准库函数std::bind1st
和std::bind2nd
的一种泛化形式。其可以支持函数对象、函数、函数指针、成员函数指针,并且绑定任意参数到某个指定值上或者将输入参数传入任意位置。
1.1 通过functions和function pointers使用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是一个占位符,表示用第一个参数来替换;
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函数的参数一般为变量的copy,如:
int i = 5; bind(f, i, _1);
比如:
void func(int a, int b, int c); boost::bind(func, 7, _1, _2);
boost::bind()
会返回一个函数对象,所以boost::bind(func, 7, _1, _2)
得到一个函数对象ob
,即ob = boost::bind(func, 7, _1, _2)
。当我们调用ob(3,4)
时,相当于调用func(7,3,4)
,如果连着一起写那就是boost::bind(func, 7, _1, _2)(3, 4)
;
需要注意的一点是,boost::bind()
里的参数个数一定要与被bind包括的函数的形参个数相同,否则这个bind函数对象ob就无法生成并报错。
如果想传入变量的引用,可以使用boost::ref
和boost::cref
,如:
int i = 5; bind(f, ref(i), _1); bind(f, cref(i), _1);
1.2 通过function objects使用bind
struct F { int operator()(int a, int b) { return a – b; } bool operator()(long a, long b) { return a == b; } }; F f; int x = 100; bind<int>(f, _1, _1)(x); // f(x, x)
可能某些编译器不支持上述的bind语法,可以用下列方式代替:
boost::bind(boost::type<int>(), f, _1, _1)(x);
默认情况下,bind拥有的是函数对象的副本,但是也可以使用boost::ref和boost::cref来传入函数对象的引用,尤其是当该function object是non-copyable或者expensive to copy。
1.3 通过pointers to members使用bind
bind将传入的成员(数据成员和成员函数)指针作为第一个参数,其行为如同使用boost::mem_fn将成员指针转换为一个函数对象,即:
bind(&X::f, args);
等价于bind<R>(mem_fn(&X::f), args)
,其中R为X::f的返回类型(成员函数)或类型(数据成员)。
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); // x.f(i) bind(&X::f, p, _1)(i); // p->f(i)
如:
cb = boost::bind(&NodeExample::configCallback, node_example, _1, _2);
其中的 node_example
是指针变量NodeExample *node_example = new NodeExample();
因此boost::bind(&NodeExample::configCallback, node_example, _1, _2)
的意思就是 node_example -> configCallback(x, y);
又如:
boost::bind(&MyNode::doneCb, this, _1, _2);
意思就是this -> doneCb(x, y)
这里的x,y 分别为第一个和第二个输入参数。
2. ROS与bind()
2.1
当我们订阅一个消息时候,会调用一个返回函数。如:
ros::Subscriber topic_sub=n.subscribe<std_msgs::Int8>("/topic", 10, Callback);
这样Callback函数应该包含一个参数,即:
void Callback(const std_msgs::Int8::ConstPtr& msg){}
但是,如果我们想要多参数传入的话,就需要使用boost库中的bind函数。例如,当我们的回调函数是这样的:
void Callback(const std_msgs::Int8::ConstPtr& msg, int& x, int& y){}
2.2 示例
#include <ros/ros.h> #include <std_msgs/Int8.h> int index1 = 1; int index2 = 2; void Callback(const std_msgs::Int8::ConstPtr &msg, int &x, int &y) { printf("%d", *msg); printf("%d \r\n", x); printf("%d \r\n", y); } void Callback(const std_msgs::Int8::ConstPtr &msg) { printf("%d \r\n", *msg); } int main(int argc, char **argv) { ros::init(argc, argv, "multi_callback"); ros::NodeHandle n; ros::NodeHandle private_nh("~"); int rate; private_nh.param("rate", rate, 40); // ros::Subscriber scan_sub=n.subscribe<std_msgs::Int8>("/topic", 10, //boost::bind(&Callback, _1, index1, index2));//① ros::Subscriber scan_sub = n.subscribe<std_msgs::Int8>("topic", 10, Callback);//② ros::Rate r(rate); while (n.ok()) { ros::spinOnce(); r.sleep(); } return 0; }
当使用①函数时:
ros::Subscriber scan_sub=n.subscribe<std_msgs::Int8>("/topic", 10, \ boost::bind(&Callback, _1, index1, index2));//①
返回函数调用的是:
void Callback(const std_msgs::Int8::ConstPtr &msg, int &x, int &y) { printf("%d", *msg); printf("%d \r\n", x); printf("%d \r\n", y); }
当使用②函数时:
ros::Subscriber scan_sub = n.subscribe<std_msgs::Int8>("topic", 10, Callback);//②
返回函数调用的是:
void Callback(const std_msgs::Int8::ConstPtr &msg) { printf("%d \r\n", *msg); }
参考资料
加载全部内容