C++ 如何调用 class 中的方法作为 TaskScheduler 的函数指针 - Arduino

C++ How to call methods within a class as function pointer for TaskScheduler - Arduino

我尝试实现一个在 C++ 中调用的任务Class,它需要一个回调函数。由于我是 C++ 的新手,虽然我对指针有粗略的了解,但这是我还无法弄清楚的事情:

我正在使用 TaskScheduler 要设置 class 中所需的一切,我想调用以下函数 arduino 的正常示例不使用 classes,我正在努力让它在我的重构代码中工作。

void Weather::setup(std::shared_ptr<Scheduler> s ,int id, String appid, uint32_t interval) 
{
  ...
  weatherTask(interval, TASK_FOREVER, &Weather::updateWeatherCallback, *scheduler, true);
}

updateWeatherCallback 函数也在这个 class 中实现:

void Weather::updateWeatherCallback() {...}

除了使用上面的代码之外,我还尝试了一些在 Whosebug 上建议的 lambda 变体以及以下内容:

weatherTask(interval,TASK_FOREVER, [this](){this->updateWeatherCallback;},*scheduler,true);

但我认为我对 Whosebug 上的这些答案的理解并不好 - 它更多的反复试验 - 这使得搜索 "the right answers" 变得困难

TaskScheduler-Library 中的一些细节:

typedef void (*TaskCallback)();
class Task {
  friend class Scheduler;
  public:
    INLINE Task(unsigned long aInterval=0, long aIterations=0, TaskCallback aCallback=NULL, 
       Scheduler* aScheduler=NULL, bool aEnable=false, TaskOnEnable aOnEnable=NULL, 
       TaskOnDisable aOnDisable=NULL);
...

谢谢:)

虽然上面使用函数指针是旧方法,但较新的方法是使用函数对象和 <functional> 库。请参阅 std::function 中的 here for an overview of the entire library, with the examples 提供了很好的 "this is how it works" 教程。

也请查看 lambdas 以了解此类问题。这也很有用,也可以存储在 std::function 中。

weatherTask 需要一个函数指针而不是指向成员的指针。解决此问题的一种可能方法是创建一个辅助结构并将函数绑定到 std::function.

#include <functional>

template <typename T>
struct Callback;

template <typename Ret, typename... Params>
struct Callback<Ret(Params...)> {
   template <typename... Args> 
   static Ret callback(Args... args) {                    
      func(args...);  
   }
   static std::function<Ret(Params...)> func; 
};

template <typename Ret, typename... Params>
std::function<Ret(Params...)> Callback<Ret(Params...)>::func;

创建 weatherTask 时使用以下方法将成员函数绑定到您的回调:

Callback<void(void)>::func = std::bind(&Weather::updateWeatherCallback, this);
TaskCallback func = static_cast<TaskCallback>(Callback<void(void)>::callback);
weatherTask(interval, TASK_FOREVER, func, *scheduler, true);

解决方案是作为 this 问题的答案提出的。由于我无法发表评论,因此我决定提供这个作为答案。


或者,您可以使用类似蹦床的功能。因此,您需要存储一个指向 Weather 对象的全局指针。

Weather global_ptr;

然后您就可以使用 lambda 函数创建 weatherTask

weatherTask(interval, TASK_FOREVER, [](){global_ptr->updateWeatherCallback();}, *scheduler, true);