Marcus A Johansson Marcus A Johansson - 3 months ago 28
C++ Question

ROS using template class member as callback for topic subscription

I'm trying to create a class that can be instantiated once, and to which one can add ros topic subscriptions where the callbacks are template specializations of the same member function.

The class ros_topic_subscriber.h file is

class ROSTopicSubscriber
{
public:

ROSTopicSubscriber() {}

~ROSTopicSubscriber() {}

template<typename ROSMessageType>
int init
(
const ros::NodeHandle &controller_nh,
const std::string& topic_name,
unsigned int buffer_size
)
{
ros::Subscriber sub = controller_nh.subscribe(
topic_name,
buffer_size,
&ROSTopicSubscriber::topicCallback<ROSMessageType>,
this
);
}

/*! \brief Implement this function for your own message!
*/
template<typename ROSMessageType>
void topicCallback(const typename ROSMessageType::ConstPtr& msg);


private:

// No copying of this class is allowed !
ROSTopicSubscriber(const ROSTopicSubscriber& other) = delete;
ROSTopicSubscriber(ROSTopicSubscriber&& other) = delete;
ROSTopicSubscriber& operator=(const ROSTopicSubscriber& other) = delete;
ROSTopicSubscriber& operator=(ROSTopicSubscriber&& other) noexcept = delete;

};


and one possible template specialization of topicCallback in my case is (in the ros_topic_subscriber.cpp file)

template<>
void ROSTopicSubscriber::topicCallback<geometry_msgs::Pose>
(
const geometry_msgs::Pose::ConstPtr& msg
)
{
std::cout << "msg\n";
}


and to make use of this class one could for example do

topic_subscriber_.init<geometry_msgs::Pose>
(n, "/wintracker/pose", 100);


Now, the compiler error I'm getting is this:

ros_topic_subscriber.h:66:3:
error: passing ‘const ros::NodeHandle’ as ‘this’ argument of
‘ros::Subscriber ros::NodeHandle::subscribe(
const string&,
uint32_t,
void (T::*)(const boost::shared_ptr<const M>&),
T*,
const ros::TransportHints&)
[with M = geometry_msgs::Pose_<std::allocator<void> >;
T = hiqp::ROSTopicSubscriber;
std::string = std::basic_string<char>;
uint32_t = unsigned int]’
discards qualifiers [-fpermissive]


Why does this error message appear in this case?
Is it possible to implement this kind of class?
How can I fix the error?

Answer

Your ROSTopicSubscriber::init gets the controller_nh parameter as a const reference which means it can only call methods that are declared as callable on a constant object. However you try to call the subscribe method which is not declared in such way.

The method declaration presumably looks like this in your code:

class NodeHandle {
    // ...
    Subscriber subscribe(/* all the parameters */);
    // ...
}

The solution depends on whether the subscribe method needs to change anything inside the NodeHandle object or not. If not, then mark it as callable on a constant object:

class NodeHandle {
    // ...
    Subscriber subscribe(/* all the parameters */) const; // <- notice const!
    // ...
}

If the subscribe method changes something inside NodeHandle, then instead you need to change the controller_nh parameter of ROSTopicSubscriber::init method to be a mutable (not constant) reference:

int init
(
    ros::NodeHandle &controller_nh, // <- notice const is gone
    const std::string& topic_name,
    unsigned int buffer_size
)