Non-static member functions require an object to work on, and thus can't be passed and called like normal function pointers.
The simplest way to make your debounce
method work, would be to use a lambda that captures your player
object and calls increment
on it:
class Button {
//...
template<typename Callback>
void debounce(Callback&& func) { // <<-- Note the && here, without
// it func would need to be
// copied
if (millis() - buttonDownTime > debounceTime) {
func();
}
}
}
void loop() {
//...
button.debounce([&player](){ player.incriment(); });
}
With a little bit of extra effort, you could implement something similar to C++17's std::invoke
to uniformly invoke any type of callable. Since you're on Arduino and don't have access to the C++ standard library, you'll need to implement std::remove_reference
and std::forward
yourself as well:
template <typename T>
struct remove_reference
{
using type = T;
};
template <typename T>
struct remove_reference<T&>
{
using type = T;
};
template <typename T>
struct remove_reference<T&&>
{
using type = T;
};
template <typename T>
constexpr T&& forward(typename remove_reference<T>::type& t)
{
return static_cast<T&&>(t);
}
template <typename T>
constexpr T&& forward(typename remove_reference<T>::type&& t)
{
return static_cast<T&&>(t);
}
template <typename Callable, typename... Args>
auto invoke(Callable&& func, Args&&... args)
-> decltype(forward<Callable>(func)(forward<Args>(args)...))
{
return forward<Callable>(func)(forward<Args>(args)...);
}
template <typename Callable, typename Class, typename... Args>
auto invoke(Callable&& method, Class&& obj, Args&&... args)
-> decltype((forward<Class>(obj).*method)(forward<Args>(args)...))
{
return (forward<Class>(obj).*method)(forward<Args>(args)...);
}
class Button {
//...
template<typename Callback, typename... Args>
void debounce(Callback&& func, Args&&... args) {
if (millis() - buttonDownTime > debounceTime) {
invoke(forward<Callback>(func),
forward<Args>(args)...);
}
}
}
void loop() {
//...
button.debounce(&Player::increment, player);
}
This doesn't quite do everything that C++17's std::invoke
does, but it's close enough to implement a basic callback. It also gives you extra flexibility in that you could pass additional arguments to debounce
and they will be passed along to your callback:
void foo(int num) { /*...*/ }
void loop() {
Button b;
b.debounce(foo, 42);
}
This doesn't really work if you need to save the callback and call it later, but it doesn't look like that's what you're trying to do.