C++:将成员函数作为普通函数指针传递的闭包 [英] C++: closure to pass member function as normal function pointer

查看:36
本文介绍了C++:将成员函数作为普通函数指针传递的闭包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试调用外部库的成员函数,该函数将函数指针作为参数:

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() {...}我的课堂::我的课堂(){//构造函数定时器 *定时器 = 新定时器();计时器->every(500, [this](){this->the_method_i_want_to_pass();})}

编译器输出:

<块引用>

警告:警告:lambda 表达式仅适用于 -std=c++11 或 -std=gnu++11 [默认启用]

错误:没有匹配的函数调用‘Timer::every(int, MyClass::MyClass()::__lambda0)’

  1. 还有其他/更好的解决方案吗?
  2. 关于我目前的方法:(如何)在需要函数指针时可以传递对 lambda 的引用?
  3. 如何确定 Arduino/AVR 是否支持这些 lambda(请参阅警告")?

解决方案

你的基本问题是你的 Timer 库写得不好:它应该采用 void(*)(void*),至少无效*.

如果没有 pvoid 或等效项,则不能在执行代码中传递地址以外的任何状态来运行过程.作为一个方法也重新绘制了一个 this 指针,你运气不好.

现在,如果您的 MyClass 实例是单例,您可以从其他地方获取 this.

否则,您需要创建自己的全局状态,以便从特定回调映射到某个状态.如果您的 MyClassTimer 的其他使用者数量有限,您可以拥有一些固定的函数,并让它们全局存储它们的额外状态.

这完全是一个黑客.接下来的事情更糟.

用一些全局状态和一个void()接口编写一个动态库.添加回调时,复制该动态库,在运行时修改其全局状态,将其写为不同名称的库,加载它,然后将纯回调函数传递给您的 Timer 类.>

或者在没有库的情况下通过手动编写机器代码并将页面标记为可执行来执行等效操作.

这些都是糟糕的解决方案.这让我想到了一个好方法:找到一个更好的 Timer.如果他们搞砸了这么简单的事情,图书馆的其他部分可能也会很糟糕.

I'm trying to call a member function of an external library which takes a function pointer as a parameter:

Timer::every(unsigned long period, void (*callback)(void));

But unfortunately the parameter I want to pass is a member function:

void MyClass::the_method_i_want_to_pass(void);

Since I'm programming for the ATMega under Arduino (AVR) there is just limited support of c++11. My first approach raises a type error:

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();})
}

Compiler Output:

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)’

  1. Are there other/better solutions?
  2. Concerning my current approach: (How) is it possible to pass a reference to a lambda when a function pointer is required?
  3. How can I find out if Arduino/AVR supports these lambdas (see "warning")?

解决方案

Your basic problem is your Timer library is poorky written: it should take void(*)(void*), void* at the least.

Without a pvoid or equivalent, you cannot pass any state other than the address in execution code to run the procedure at. As a method also rewuires a this pointer, you are out of luck.

Now, if your instance of MyClass is a singleton, you can get this from somewhere else.

Failing that, you need to make your own global state that lets you map from a particular callback to some state. If you have a limited number of MyClass and other consumers of Timer, you can have a few fixed functiins, and have them store their extra state globally.

This is all a hack. What follows is worse.

Write a dynamic library with some global state, and a void() interface. When you add a callback, duplicate that dynamic library, modify its global state at runtime, write it out as a differently named library, load it, and pass the pure callback function to your Timer class.

Or do the equvalent without a library by manually writing machine code and marking pages as execuable.

These are all poor solutions. Which leads me to a good one: find a better Timer. If they screwed up something that simple, the rest of the library is probably bad as well.

这篇关于C++:将成员函数作为普通函数指针传递的闭包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆