嗨,我想将成员函数作为参数传递给构造函数其他类。我尝试了很多解决方案,但都给我失败了。 所以.. 头等舱。
class WebSocketsServerRunner : public WebSocketsServer {
private:
ThreadController<uint8_t> threads = ThreadController<uint8_t>();
SensorsState sensorsState;
void notifyClient(uint8_t clientNumber) { // this is the callback
String message = sensorsState.readAsJSON();
WebSocketsServer::sendTXT(clientNumber, message);
}
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
// solution bellow doesn't work!
Thread<uint8_t>* thread = new Thread<uint8_t>(static_cast<int>(num), &WebSocketsServerRunner::notifyClient, num, 5000);
threads.add(thread);
}
};
和线程构造函数声明:
Thread(int _id, void (*callback)(void) = NULL, long _interval = 0);
Thread(int _id, void (*callback)(Arg), Arg arg, long _interval = 0);
其中Arg为template <typename Arg>
我尝试了所有方法。std :: bind,&CLASS_NAME :: METHOD_NAME,static_cast,但无济于事。
编译给我:
no known conversion for argument 2 from 'void (WebSocketsServerRunner::*)(uint8_t) {aka void (WebSocketsServerRunner::*)(unsigned char)}' to 'void (*)(unsigned char)'
...
no matching function for call to 'Thread<unsigned char>::Thread(int, void (WebSocketsServerRunner::*)(uint8_t), uint8_t&, int)'
答案 0 :(得分:0)
成员函数的指针与普通函数的指针具有不同的语法:
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)();
请注意,.*
和->*
运算符的优先级都低于函数调用运算符()
(如果是一个好的决定,可能会争论不休,但实际上是这样。) 。),因此需要括号。
下面我仅出于说明作用展示成员函数的性质,请注意,这实际上是未定义的行为(但很可能起作用)– < strong>永远不要在生产性代码中使用它们:
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);
有趣的一面是,引用和指针都应该发挥作用,这表明,在幕后,引用(如果被实例化的话)也不过是指针,而仅仅是应用了特定的规则(因此,最后,语法糖)。
尽管上面还揭示了调用成员函数,即使您非法使用普通的函数指针,您仍然需要一个可以在其上调用函数的对象!
那有哪些选择呢?
static
成员函数没有透明的this
函数参数,即。 e。它们可以像任何普通函数一样使用:
static void notifyClient(uint8_t clientNumber)
// ^^^ (!)
{
WebSocketsServerRunner& instance = selectById(clientNumber);
String message = instance.sensorsState.readAsJSON();
WebSocketsServer::sendTXT(clientNumber, message);
}
如果无法使用客户端编号获取实例,则必须修改Thread
类,使其保留用于调用该函数的对象。
大多数泛型(不一定是最安全的)正在使用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))
{ }
};
这可以喂lambda:
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);
编辑:根据您的评论,不适合...