我正在尝试调用外部库的成员函数,该函数将函数指针作为参数:
Timer::every(unsigned long period, void (*callback)(void));
但不幸的是,我要传递的参数是一个成员函数:
void MyClass::the_method_i_want_to_pass(void);
由于我正在为Arduino(AVR)下的ATMega编程,因此对c ++ 11的支持有限。我的第一种方法引发了类型错误:
void MyClass::the_method_i_want_to_pass() {...}
MyClass::MyClass() {
// constructor
Timer *timer = new Timer();
timer->every(500, [this](){this->the_method_i_want_to_pass();})
}
编译器输出:
警告:警告:lambda表达式仅适用于-std = c ++ 11或-std = gnu ++ 11 [默认启用]
错误:没有匹配函数来调用'Timer :: every(int,MyClass :: MyClass():: __ lambda0)'
答案 0 :(得分:1)
您的基本问题是您的Timer
图书馆写得很糟糕:至少应该void(*)(void*), void*
。
如果没有pvoid或等价物,则不能传递执行代码中的地址以外的任何状态来运行该过程。作为一种方法也可以重新使用this
指针,你运气不好。
现在,如果您的MyClass
实例是单身,则可以从其他地方获取this
。
如果失败,您需要创建自己的全局状态,以便将特定回调映射到某个状态。如果您的MyClass
和Timer
的其他消费者数量有限,您可以拥有一些固定的功能,并让他们在全球范围内存储他们的额外状态。
这都是黑客攻击。接下来的情况更糟。
编写具有某种全局状态和void()
接口的动态库。添加回调时,复制该动态库,在运行时修改其全局状态,将其写为不同名称的库,加载它,并将纯回调函数传递给Timer
类。
或者在没有库的情况下通过手动编写机器代码并将页面标记为可执行来实现等效。
这些都是糟糕的解决方案。这引导我找到一个好的:找到一个更好的Timer
。如果他们搞砸了一些简单的东西,那么图书馆的其余部分也可能很糟糕。