Home > database >  Question regarding the use of std::bind in ROS2 tutorial
Question regarding the use of std::bind in ROS2 tutorial

Time:10-17

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
}
  • Related