Указатели на функции-члены имеют синтаксис, отличный от обычных указателей на функции:
void(*function)(); // pointer to function
void(YourClass::*memberFunction)(); // pointer to member function
Причина заключается в том, что функции-члены имеют дополнительный скрытый / прозрачный параметр, принимающий объект, для которого вызывается функция, и который представляетсявы как this
указатель.
Таким образом, вызов функции-члена также отличается (вам нужен объект для вызова функции):
void(YourClass::*memberFunction)() = &YourClass::someFunction;
YourClass instance;
YourClass* pointer = &instance;
(instance.*memberFunction)();
(pointer->*memberFunction)();
Помните, что и .*
, и->*
операторы имеют более низкий приоритет, чем оператор вызова функции ()
(если бы это было хорошее решение, можно было бы поспорить, но это так, как есть ...), поэтому вам нужно круглые скобки.
Ниже я покажу только для иллюстрации природы функций-членов, учтите, что это на самом деле неопределенное поведение (но, скорее всего, это сработает) - не когда-либо используйте это в производительном коде :
void(*functionR)(YourClass&)
= reinterpret_cast<&void(*)(YourClass&)(&YourClass::someFunction);
void(*functionP)(YourClass*)
= reinterpret_cast<&void(*)(YourClass*)(&YourClass::someFunction);
YourClass instance;
YourClass* pointer = &instance;
functionR(instance);
functionP(pointer);
Интересным аспектом является то, что и ссылка, и указатель должны делать свое дело, открываяпод капотами ссылки - если они вообще создаются - являются не более чем указателями, исключительно с применением конкретных правил (так, в конце концов, синтаксический сахар).
Выше также видно, чтовызовите функцию-член, даже если вы незаконно используете обычный указатель на функцию, вам все еще нужен объект, для которого вы можете вызвать функцию!
Итак, какие есть варианты?
*Функции-члены 1035 *
static
не имеют прозрачного параметра функции
this
, то есть они могут использоваться как любая обычная функция:
static void notifyClient(uint8_t clientNumber)
// ^^^ (!)
{
WebSocketsServerRunner& instance = selectById(clientNumber);
String message = instance.sensorsState.readAsJSON();
WebSocketsServer::sendTXT(clientNumber, message);
}
Если вы не можете получить экземпляр, используя номер клиента, выПридется изменить класс Thread
так, чтобы он также содержал объект для вызова функции.
Most generic , не обязательно самый безопасный, хотя используетvoid*
указатель:
class Thread
{
void(*function)(void*);
void* parameter;
void run()
{
function(parameter);
}
};
Теперь вы можете использовать статический член и обычные функции, но вам нужно привести параметр обратно, чтобы получить экземпляр, кроме того, вы не можете использоватьумные указатели для безопасного управления памятью.Лучший подход:
template <typename T>
class Thread
{
std::function<void(T*)>;
std::shared_ptr<T> instance;
void run()
{
function(instance.get());
}
public:
template <typename F>
Thread(F function, std::shared_ptr<T>& instance)
: function(function), instance(instance)
{ }
};
Интересно то, что вы можете хранить как указатель на функцию-член, так и отдельно стоящие функции в объекте std :: function.Другой вариант:
template <typename T>
class Thread
{
T t;
void run()
{
t();
}
public:
Thread(T&& t)
: t(std::move(t))
{ }
};
Этот код можно кормить лямбдами:
Thread t([&instance]() { instance.doSomething(); });
Возможно, это будет интересная альтернатива прямому использованию std::thread
:
class WebSocketsServerRunner
{
public:
static void run(uint8_t clientNumber)
{
WebSocketsServerRunner instance;
for(;;)
{
// do whatever your Thread class did
}
}
};
std::thread t10(&WebSocketsServerRunner::run, 10U);
std::thread t12(&WebSocketsServerRunner::run, 12U);
Редактировать: по вашим комментариям не подходит ...