Как передать нестатический член класса в обратный вызов?
Я использую библиотеку arduinoWebSockets в своей собственной библиотеке Arduino. У меня возникли проблемы с попыткой назначить член класса в качестве функции обратного вызова onEvent
библиотеки веб-сокетов.
MyClass.cpp:
#include <WebSocketsClient.h>
#include "Arduino.h"
#include "MyClass.h"
void MyClass::connect(String host, int port) {
webSocket.begin(host, port, "/");
webSocket.setReconnectInterval(5000);
// попробовал все эти варианты
// webSocket.onEvent(incomingEventHandler);
// webSocket.onEvent(MyClass::incomingEventHandler);
webSocket.onEvent(this->incomingEventHandler);
}
void MyClass::loop() {
webSocket.loop();
}
void MyClass::incomingEventHandler(WStype_t type, uint8_t *payload, size_t length) {
// делаем что-то с входящими данными
// нужен доступ к другим функциям-членам и переменным класса
}
MyClass.h:
#ifndef MyClass_h
#define MyClass_h
#include <WebSocketsClient.h>
#include "Arduino.h"
class MyClass {
public:
void connect(String host, int port);
void loop();
void incomingEventHandler(WStype_t type, uint8_t *payload, size_t length);
private:
WebSocketsClient webSocket;
};
#endif
Возвращается ошибка:
sketch/MyClass.cpp: в функции-члене void MyClass::connect(String, int)': MyClass.cpp:14:47: ошибка: нет соответствующей функции для вызова 'WebSocketsClient::onEvent()'
webSocket.onEvent(this->incomingEventHandler);
Насколько я понимаю, мне нужно создать указатель на член класса. Я пробовал несколько разных способов, этот показался наиболее многообещающим, но все равно не удалось:
typedef void (MyClass::*MyClassMemFn)(WStype_t type, uint8_t *payload, size_t length);
void MyClass::connect(String host, int port) {
webSocket.begin(host, port, "/");
webSocket.setReconnectInterval(5000);
MyClassMemFn onEventCallback = &MyClass::incomingEventHandler;
webSocket.onEvent(MyClassMemFn onEventCallback);
}
Приведенное выше возвращает эту ошибку:
sketch/MyClass.cpp: в функции-члене void MyClass::connect(String, int)': MyClass.cpp:15:34: ошибка: ожидалось первичное выражение раньше 'onEventCallback' webSocket.onEvent(MyClassMemFn onEventCallback);
Я также пытался использовать std::bind
:
void MyClass::connect(String host, int port) {
webSocket.begin(host, port, "/");
webSocket.setReconnectInterval(5000);
webSocket.onEvent(std::bind(&MyClass::incomingEventHandler, this));
}
Ошибка:
sketch/MyClass.cpp: в функции-члене void MyClass::connect(String, int)': MyClass.cpp:12:47: ошибка: нет соответствующей функции для вызова 'WebSocketsClient::onEvent()'
webSocket.onEvent(this->incomingEventHandler);
Если я перенесу функцию incomingEventHandler
за пределы определения класса, она будет работать как положено, однако тогда я не смогу вызывать другие члены класса или получать доступ к свойствам класса в той же области видимости.
Как в Arduino C++ передать нестатические свойства членов класса в качестве обратного вызова? Есть ли лучший способ подойти к этому?
@oznu, 👍2
Обсуждение1 ответ
Лучший ответ:
Да, обратный вызов может быть функцией-членом. Ошибка в вашем вызове std::bind
заключается в том, что, хотя вы привязываете первый скрытый параметр this
к экземпляру объекта, в данном случае this
объект, вы также должны использовать заполнители для всех других параметров функции.
Поскольку вы заявили
void incomingEventHandler(WStype_t type, uint8_t *payload, size_t length)
Вы должны привязаться как
webSocket.onEvent(std::bind(&MyClass::incomingEventHandler, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
Обратите внимание, что этот вызов webSocket.onEvent
работает только в том случае, если вы используете платформу, отличную от AVR, поскольку библиотека определяет
void WebSocketsClient::onEvent(WebSocketClientEvent cbEvent) {
_cbEvent = cbEvent;
}
с
#ifdef __AVR__
typedef void (*WebSocketClientEvent)(WStype_t type, uint8_t * payload, size_t length);
#else
typedef std::function<void (WStype_t type, uint8_t * payload, size_t length)> WebSocketClientEvent;
#endif
т.е. это необработанный указатель на функцию в __AVR__
, но std::function
на платформах, отличных от AVR — std::bind
даст вам std::function
. Поскольку у вас ESP8266, все должно работать нормально.
Обратитесь к https://en.cppreference.com/w/cpp/utility/functional/bind (и, возможно, мой старый вопрос)< /п>
- Передача функции-члена класса в качестве аргумента
- контент» не захватывается
- esp32 Stack canary watchpoint срабатывает
- Преобразование byte* в int в Arduino
- ESP8266: ошибка: 'getLocalTime' was not declared in this scope
- Какова цель F() и FPSTR() в ESP8266WebServer -> FSBrowser?
- Веб-сервер ESP8266 не отвечает (тайм-аут подключения)
- ESP8266 ISO 8601 string to tm struct
@asked На самом деле это вопрос о том, как работает C++. Магия заключается в обработке
this
. Функции-члены имеют "скрытый" параметр.This
необходим для предоставления доступа к данным-членам и таблице виртуальных функций. Поэтому краткий ответ на ваш вопрос таков: обратный вызов не может быть функцией-членом., @Mikael Patel