c++templatesros

How do we infer the way create_publisher should be defined in ROS from the documentation?


I would like to correlate the ROS documentation with its reference examples. This is a nit-picking, but I would like to know if it's ROS specific or generic C++ implementation.

Consider the create_publisher() function defined in ROS here

template<typename MessageT , typename Alloc , typename PublisherT >
std::shared_ptr< PublisherT > rclcpp::Node::create_publisher    (   const std::string &     topic_name,
size_t  qos_history_depth,
std::shared_ptr< Alloc >    allocator = nullptr 
)       

Create and return a Publisher.

Parameters

[in]    topic_name  The topic for this publisher to publish on.
[in]    qos_history_depth   The depth of the publisher message queue.
[in]    allocator   Optional custom allocator.

Returns

Shared pointer to the created publisher.

Now, consider the code sample in its example for Creating a Publisher - here

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));
    } 
}

Here, if we look at the definition of publisher_ shared pointer, it takes template parameter std_msgs::msg::String as input, and parameters- topic name and size_t as non-type parameters. Based on some of my findings, this is a template function. So, is the right way to define such functions something like-

create_publisher<typename MessageT , typename Alloc , typename PublisherT > (   const std::string &     topic_name,
    size_t  qos_history_depth,
    std::shared_ptr< Alloc >    allocator = nullptr 
    )   

Also, that would mean Node is the template class. Then how do we access the member function without initializing the class? Does it take place in the background?

I think I am bit confused with the whole template implementation, as it doesn't follow the syntax from the template tutorials that I have seen till now.


Solution

  • The doxygen autogenerated docs are missing some details. If you look at the implementation:

      template<
        typename MessageT,
        typename AllocatorT = std::allocator<void>,
        typename PublisherT = rclcpp::Publisher<MessageT, AllocatorT>>
      std::shared_ptr<PublisherT>
      create_publisher(
        const std::string & topic_name,
        const rclcpp::QoS & qos,
        const PublisherOptionsWithAllocator<AllocatorT> & options =
        PublisherOptionsWithAllocator<AllocatorT>()
      );
    

    you see that second and third template parameters have default values, so you only need to specify the MessageT, that will imply the publisher returned type. So, if you call

    auto pub = _myNode->create_publisher<String>("chatter", 10);
    

    the pub will have a type std::shared_ptr<rclcpp::Publisher<String, std::allocator<void>>>.

    class Node itself is not a template, it just has templated create_publisher method.

    In MinimalPublisher example authors suggest to subclass rclcpp::Node, probably for convenience - to be able to pass it directly to rclcpp::spin function, and to make sure that publishers/timers lifetime do not exceed the lifetime of provided callback. But in principle you could achieve similar behavior by working directly with std::make_shared<rclcpp::Node>(...).