ROS订阅器中为何使用std::bind?需指定对象与占位符的原因
1. 为什么不能直接传入成员函数/指针,必须用std::bind?
C++的类成员函数和普通全局函数有个核心区别:成员函数默认带有一个隐藏的this参数,用来指向调用该函数的类实例。
以ROS中处理std_msgs::String的回调为例,ROS订阅器期望的回调签名是:
void(const std_msgs::String::ConstPtr&)
但你的类成员函数topic_callback的实际签名是:
void YourNodeClass::topic_callback(const std_msgs::String::ConstPtr&)
本质上等价于:
void topic_callback(YourNodeClass* this, const std_msgs::String::ConstPtr&)
这个签名和ROS要求的不匹配——ROS只准备传递消息参数,不知道该怎么提供this指针。std::bind的作用就是把this指针和成员函数绑定在一起,生成一个符合ROS要求签名的可调用对象,把隐藏的this参数固定下来。
而Python中成员方法在绑定到实例时,会自动把实例作为第一个参数(self)传递,不需要手动处理,所以可以直接传方法对象。
2. 引用成员函数时已关联对象,为何还要指定this?
你可能混淆了成员函数指针和绑定了实例的方法对象。&YourNodeClass::topic_callback只是一个指向类成员函数的指针,它并不关联任何具体的类实例——同一个成员函数指针可以用来调用任意该类实例的对应方法。
比如你有两个YourNodeClass的实例:
YourNodeClass node1; YourNodeClass node2;
如果不指定this,std::bind根本不知道要调用node1.topic_callback还是node2.topic_callback。所以必须通过this(或者实例的地址)明确告诉std::bind,要绑定到哪个具体的实例上,这样回调触发时才会调用该实例的成员函数。
3. 仅需传入一个String参数,为何要使用_1占位符?
_1是std::placeholders命名空间下的占位符,用来表示“这个位置的参数由调用者提供”。
当你用std::bind(&YourNodeClass::topic_callback, this, _1)时:
- 第一个参数是成员函数指针
- 第二个参数
this是固定传递给成员函数的隐藏参数 _1表示:回调被调用时,调用者(ROS订阅系统)传入的第一个参数,会被传递给topic_callback的第二个参数(也就是消息参数)
如果不使用_1,而是直接传一个固定值,比如std::bind(&YourNodeClass::topic_callback, this, some_string),那生成的可调用对象就不需要外部传参了,这和ROS期望的回调签名完全不符——ROS需要传递消息参数,而你绑定了固定值,程序运行时必然会出错。
内容的提问来源于stack exchange,提问作者Manish

