关于在 ROS2 教程中使用 std::bind 的问题

Posted

技术标签:

【中文标题】关于在 ROS2 教程中使用 std::bind 的问题【英文标题】:Question regarding the use of std::bind in ROS2 tutorial 【发布时间】:2021-10-16 23:05:22 【问题描述】:

我对 C++ 相当陌生,我对 std::bind 的做法有疑问。下面的 sn-p 就是从这个tutorial on the ROS2 website 复制过来的。该代码创建了一个类,其中 timer_ 字段承载了一个使用create_wall_timer() 创建的计时器。 creates_wall_timer() 接受 CallbackT && 类型的回调对象。在类的构造函数中,为什么作者将std::bind(...)的结果作为回调传递给create_timer(),而不是直接指针或引用timer_callback方法?

对冗长的问题表示歉意。我不太擅长问这些问题。希望我没有错过您需要的太多信息。

#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_;
;

【问题讨论】:

我们需要create_wall_timer的声明。但很可能create_wall_timer 接受一个没有参数的函数对象,而一个成员方法有一个隐藏的this 参数,这就是使用bind 的原因。 【参考方案1】:

您不能单独传递指向成员函数的指针(除非该函数声明为 static),因为它需要调用 [正确类型] 对象的实例。

std::bind 将一个指向对象的指针(在本例中为this)绑定到成员函数指针(&amp;MinimalPublisher::timer_callback),以便在调用该函数时,有一个所需的实例/所需的对象可用。

要从另一个(更简单)的角度来看待这个问题,考虑一下如果你这样写会发生什么:

MinimalPublisher::timer_callback ();

如果 MinimalPublisher::timer_callback 不是 static 函数,编译器会报错,因为只能通过 [pointer to a] MinimalPublisher 对象调用非静态函数,因此类似于:

my_minimal_publisher_object.MinimalPublisher::timer_callback ();

或:

my_minimal_publisher_object_pointer-&gt;MinimalPublisher::timer_callback ();

您可能想在您的favourite online compiler 中进行此实验。

顺便说一句,std::bind 在很大程度上已被 capturing lambdas 取代。因此,为了捕获所需的对象实例(并以我在 Wandbox 的原始示例为起点),you might do:

#include <functional>

struct MyStruct

    void foo ();
;

int main()

    MyStruct s;
    std::function <void ()> f = [&s]  s.foo (); ;
    // Do things with f

【讨论】:

这是否意味着一个类中的所有非静态函数在技术上都有一个“this”参数?根据我在 std::bind 上阅读的内容,它使用用户提供的参数填充函数。 是的,正是如此。没有this 指针,没有交易。 std::bind 所做的是将成员函数指针和指向对象的指针包装成 std::function,以便在调用函数时用作 this。如果成员函数签名需要它们,您还可以指定更多参数。 'this 必须是 std::bind 的第一个参数,并且任何其他参数必须跟随(按适当的顺序)。

以上是关于关于在 ROS2 教程中使用 std::bind 的问题的主要内容,如果未能解决你的问题,请参考以下文章

std::bind 有多少个参数(VC 11 只支持 4 个)

ROS2初学者教程(Dashing和Eloquent)Windows

std::function与std::bind使用总结

Emscripten 和从 std::bind 到 std::function 的转换

使用 std::bind 占位符和 boost 库的问题

ROS2学习笔记25--ros2话题统计编写教程(C++)