我正在尝试调用一个以函数指针作为参数的外部库的成员函数:
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();})
}
编译器输出:
warning: warning: lambda expressions only available with -std=c++11 or -std=gnu++11 [enabled by default]
error: no matching function for call to ‘Timer::every(int, MyClass::MyClass()::__lambda0)’
- 是否有其他/更好的解决方案?
- 关于我当前的方法:(如何)在需要函数指针时可以传递对 lambda 的引用?
- 如何确定 Arduino/AVR 是否支持这些 lambda(参见“警告”)?
最佳答案
你的基本问题是你的 Timer
库写得很糟糕:它至少应该使用 void(*)(void*), void*
。
如果没有 pvoid 或等效项,除了执行代码中的地址之外,您不能传递任何状态以运行过程。作为一个方法也需要一个 this
指针,你真倒霉。
现在,如果您的 MyClass
实例是单例,您可以从其他地方获取 this
。
否则,您需要创建自己的全局状态,让您可以从特定回调映射到某个状态。如果您的 MyClass
和 Timer
的其他消费者数量有限,您可以拥有一些固定的函数,并让它们全局存储它们的额外状态。
这都是黑客。接下来的事情更糟。
用一些全局状态和一个void()
接口(interface)写一个动态库。添加回调时,复制该动态库,在运行时修改其全局状态,将其写出为不同名称的库,加载它,并将纯回调函数传递给您的 Timer
类。
或者通过手动编写机器代码并将页面标记为可执行来在没有库的情况下执行等效操作。
这些都是糟糕的解决方案。这让我想到了一个好方法:找到一个更好的 Timer
。如果他们搞砸了这么简单的事情,图书馆的其他部分可能也很糟糕。
关于C++:将成员函数作为普通函数指针传递的闭包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24352785/