I am fairly new to C and I have a question regarding practices of std::bind. The following snippet is copied from this tutorial on the ROS2 website. The code creates a class where the timer_ field hosts a timer that is created using create_wall_timer()
. creates_wall_timer()
accepts a callback object of type CallbackT &&
. In the constructor of the class, why does the author pass the result of std::bind(...)
as the callback to create_timer()
instead of a direct pointer or reference to the timer_callback method?
Apologies for the long questions. I am not really good at asking these questions. Hopefully, I didn't miss too much information that you need.
#include <chrono>
#include <functional>
#include <memory>
#include <string>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
using namespace std::chrono_literals;
/* This example creates a subclass of Node and uses std::bind() to register a
* member function as a callback from the timer. */
class MinimalPublisher : public rclcpp::Node
{
public:
MinimalPublisher()
: Node("minimal_publisher"), count_(0)
{
publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);
timer_ = this->create_wall_timer(
500ms, std::bind(&MinimalPublisher::timer_callback, this));
}
private:
void timer_callback()
{
auto message = std_msgs::msg::String();
message.data = "Hello, world! " std::to_string(count_ );
RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
publisher_->publish(message);
}
rclcpp::TimerBase::SharedPtr timer_;
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
size_t count_;
};
CodePudding user response:
You can't pass a pointer to a member function in isolation (unless that function is declared static
), because it needs an instance of the [right kind of] object to be called on.
std::bind
binds a pointer to an object (this
, in this example) to the member function pointer (&MinimalPublisher::timer_callback
) so that when the time comes to call the function, there is an instance of the required / desired object available.
To look at this from another (simpler) angle, consider what happens if you write:
MinimalPublisher::timer_callback ();
If MinimalPublisher::timer_callback
is not a static
function the compiler will complain, because a non-static function can only be called through a [pointer to a] MinimalPublisher
object, so something like:
my_minimal_publisher_object.MinimalPublisher::timer_callback ();
or:
my_minimal_publisher_object_pointer->MinimalPublisher::timer_callback ();
You might like to experiment with this in your favourite online compiler.
Incidentally, std::bind
has been largely superseded by capturing lambdas these days. So, in order to capture the required object instance (and taking my original example over at Wandbox as a starting point), you might do:
#include <functional>
struct MyStruct
{
void foo ();
};
int main()
{
MyStruct s;
std::function <void ()> f = [&s] { s.foo (); };
// Do things with f
}