ISO C++ запрещает принимать адрес неквалифицированной или заключенной в скобки нестатической функции-члена для формирования указателя на функцию-член

Этот вопрос следует за этим вопросом

В последнем вопросе я узнал, как использовать список инициализаторов для решения моей проблемы, но работа с ros::Subscriber требует другого решения.

В этом сценарии я имею дело с обратным вызовом. Если я оставлю обратный вызов как отдельную функцию, то программа запустится, но у меня нет доступа к членам класса и методам внутри функции, что противоречит цели. Вот мой автономный обратный вызов:

void setPRYCallback( const std_msgs::Empty& toggle_msg) {}

Как только я перемещаю это в свой класс, я сталкиваюсь с ошибкой.

шаги к внедрению в класс

// добавить переменную-член для
protected:
  void setPRYCallback( const std_msgs::Empty& );

...

// ass метод
void ROSController::setPRYCallback( const std_msgs::Empty& toggle_msg) {}

...

// установить список инициализаторов
ROSController::ROSController() : sub("setPRY", &setPRYCallback )

Как мне предотвратить эту ошибку, сохраняя мой обратный вызов в качестве метода класса?

Программа с автономной функцией обратного вызова (программа запускается)

#include <ros.h> // https://github.com/ros-drivers/rosserial/blob/jade-devel/rosserial_arduino/src/ros_lib/ros.h
#include <std_msgs/Empty.h>

class ROSController {
  protected:
    ros::Subscriber<std_msgs::Empty> sub;
    ros::NodeHandle _nh;
  public:
    void loop();
    ROSController();
};

void setPRYCallback( const std_msgs::Empty& toggle_msg) {}

ROSController::ROSController()  {
  this->_nh.initNode();
  this->_nh.subscribe(sub);
}

void ROSController::loop() {
  this->_nh.spinOnce();
  delay(1000);
}

Программа с обратным вызовом метода (сбой программы)

#include <ros.h> // https://github.com/ros-drivers/rosserial/blob/jade-devel/rosserial_arduino/src/ros_lib/ros.h
#include <std_msgs/Empty.h>

class ROSController {
  protected:
    ros::Subscriber<std_msgs::Empty> sub;
    ros::NodeHandle _nh;
    void setPRYCallback( const std_msgs::Empty& );
  public:
    void loop();
    ROSController();
};

void ROSController::setPRYCallback( const std_msgs::Empty& toggle_msg) {}

ROSController::ROSController() : sub("setPRY", &setPRYCallback )  {
  this->_nh.initNode();
  this->_nh.subscribe(sub);
}

void ROSController::loop() {
  this->_nh.spinOnce();
  delay(1000);
}

arduino mega

, 👍2

Обсуждение

Есть ли где-нибудь, где мы можем увидеть эту библиотеку "ros.h", которую вы используете?, @Majenko

Это сделает трюк: https://github.com/NimbRo/nimbro-op-ros/blob/master/src/nimbro/contrib/roscpp/include/ros/ros.h, @Jacksonkr

Начните с того, что сделайте "setPRYCallback" статическим., @Mikael Patel


2 ответа


Лучший ответ:

2

Когда вы перемещаете функцию setPRUCallback в свой класс, вы меняете прототип (ну, C++ меняет прототип) с:

void setPRYCallback( const std_msgs::Empty& toggle_msg) {}

Для:

void setPRYCallback( ROSController *this, const std_msgs::Empty& toggle_msg) {}

Теперь это не то, что ожидает функция регистрации обратного вызова, и поэтому она ломается.

Делая метод статическим, он удаляет этот параметр *this, но также означает, что функция может получить доступ только к статическим данным внутри вашего класса (переменные также помечены как статические), и существует только одна копия функции (и статические переменные), разделяемая между всеми экземплярами класса (возможно, не то, что вы хотите)..

,

2

Если вы определяете экземпляр как глобальное значение, как насчет того, чтобы установить обратный вызов с использованием лямбда-выражения в качестве переменной конструктора.

#include <ros.h>
#include <std_msgs/Empty.h>

class ROSController {
  protected:
    ros::Subscriber<std_msgs::Empty> sub;
    ros::NodeHandle nh;
  public:
    ROSController(void (*staticPRYCallback)(const std_msgs::Empty& msg));
    void begin();
    void loop();
    void setPRYCallback( const std_msgs::Empty& );
};

void ROSController::setPRYCallback(const std_msgs::Empty& toggle_msg) {}

ROSController::ROSController(void (*staticPRYCallback)(const std_msgs::Empty& msg))
  : sub("setPRY", staticPRYCallback )  {
}

void ROSController::begin() {
  nh.initNode();
  nh.subscribe(sub);
}

void ROSController::loop() {
  nh.spinOnce();
}

ROSController rosController([](const std_msgs::Empty& msg){
  rosController.setPRYCallback(msg);
});

void setup() {
  rosController.begin();
}

void loop() {
  rosController.loop();
  delay(1000);
}

Ссылка (пост моего блога на японском языке)
https://asukiaaa.blogspot.com/2020/09/define-cpp-callback-for-class-value-with-using-lambda-as-a-variable.html

,