1

This question is somewhat similar to How to pass non-static class member to callback?, but there are a few differences, especially since a lot of my uses have "interesting" additional complexities. I'd like to understand better my options in using them, since I have not gained enough understanding from other answers (and I need to write both the callback and the function that calls it).

I have a number of libraries that produce "events" that I'd like to be able to write separate classes or functions to respond to (so I don't need to customize every library every time I develop something). The annoying part is that I've long-since discovered the this pointer that's hidden in class method calls, which prevents me from passing currentgui.leftbutton as a function to menu.leftbuttonpressed(void (*callbackfuncptr)(void)).

I'm also using the ESP8266 web server library, which needs a callback in the context of the server object that can call the server as a global to actually get the data sent to it! (Unless the server passes its own this as a parameter to the callback, which I don't know since the documentation consists almost solely of a small number of "examples" which don't show the majority of the actual features of the web server, rather than a real explanation.)

I could use some variant of a pointer to a class method, but the syntax for that is eye-gouging and I'm using more than one class to provide callbacks to (especially for the task scheduler), so this would require customizing the library to handle pointers to every class I use again. I can't use polymorphism, either, since some classes contain multiple scheduler callbacks to be done on different times/conditions.

How do I handle these callbacks? My current method is to write a function that wraps the method's function, but that relies on a specific instance of that method, so it can't be reused. It's also really awkward since I'm now dealing with multiple functions/methods that are now very similar.

I would also like to be able to have a class, that when passed a web server object, registers itself as a callback to a particular page event (I want to write a network connection manager similar to the WiFiManager library, but with the ability to integrate with an existing webpage. I have all the code, but it currently can't be nicely integrated into a standalone class because of this issue). It needs to store a pointer to the server object to get the data once the callback's called, but it also needs to be attached to the callback of the class that holds that particular pointer AND the other handler functions once the data's retrieved. There is already a library that does something similar, but I can't figure out at all how this works, since I was under the impression that this is not possible. Can someone help me understand how the following class operates? https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266HTTPUpdateServer/src

6
  • Can you clarify ... if the server needs a callback, and you provide a callback, are you expecting to access server variables or functions? If so, your callback would need to be derived from the server class would it not? Can someone help me understand how the following class operates - this is rather a broad question. A quick glance seems to show it is using lambda functions and templates, but apart from that I think you will need to narrow down what it is you want to know.
    – Nick Gammon
    Commented Aug 19, 2019 at 4:57
  • 1
    the ESP8266HTTPUpdateServer registers a lambda function as server->on handler. a lambda function is not a member of a class
    – Juraj
    Commented Aug 19, 2019 at 8:11
  • The Object-Oriented Programming (OOP) way of doing this is to use virtual member functions and subclassing. This allows access to the member data. A callback will require the object as a parameter but will not have access to private or protected member data or functions. Commented Aug 19, 2019 at 13:29
  • @NickGammon, It uses normal functions, not ones that derive from the class. They call the same instance of the class' member functions to get data back. I'd like to know how to get a class I wrote (nothing special about it, but how do I connect it?) to register itself as a callback so IT gets data and I don't need a bunch of disconnected non-class functions around.
    – user47164
    Commented Aug 20, 2019 at 14:45
  • @Juraj, I begin to think that might be it. Can you post an answer explaining more and how exactly they did that? If the function is inline but not part of the class, that would work, I think... But how do they still get access to class members in it?
    – user47164
    Commented Aug 20, 2019 at 14:46

2 Answers 2

1

The ESP8266WebServer uses callback functions to handle HTTP request by your code. This callback functions can't be members of a class. But you can use anonymous functions to implement this callbacks. And if you like you can implement them as 'redirects' to functions of your objects.

server.on("/leftbutton", []() {
  currentgui.leftbutton(server); 
}

Note: this anonymous functions are called lambda functions and they can do some tricks with parameters too

2
  • Bonus Internet points for the link. Looks like I need to figure out how those capture clauses work, though, since it looks like that example uses them... Thanks!
    – user47164
    Commented Aug 22, 2019 at 17:55
  • I have since run into issues doing this with my own callback-accepting functions, as it would appear that lambdas have a compiler-defined type. How do I write callback-handling code that can take a lambda?
    – user47164
    Commented Feb 13, 2022 at 5:58
0

They call the same instance of the class' member functions to get data back.

Yes, but if they eventually call the class' member function to get data, other than static data, then the need to know what instance of the class to get the data from.

I'd like to know how to get a class I wrote (nothing special about it, but how do I connect it?) to register itself as a callback so IT gets data and I don't need a bunch of disconnected non-class functions around

If function X (not a member of this class) needs to be able to access the data from instance A or instance B then clearly X needs to know which instance it is looking at (the this pointer). This is not a syntax thing, you need to have a way of solving this problem.

In fact, when you say "a class I wrote" then that would also have instance data (its own this) so now you are trying to connect two instances of two classes.

How many server objects do you have? If just one in this particular case you might be able to fudge your way around it by storing its this somewhere, or making some glue routines.

5
  • Yes, but if they eventually call the class' member function to get data, other than static data, then the need to know what instance of the class to get the data from. -- yes, that's the problem. I need to store the this per-instance of MY class, but also connect a member of my class TO its callback, so the callback gets my instance that can access ITS instance! Connecting two instances of two classes -- yes, exactly. There should be a way to do this, right? Someone said something about lambda functions being used in the existing example, but I don't understand what they did.
    – user47164
    Commented Aug 21, 2019 at 17:57
  • A lambda function is just an anonymous function. That is, you can put a lambda function "inline" instead of having to name a function declared elsewhere. Other than that, they don't help solve this problem. I think you need to make up an example and edit that into your question. And to be honest I think this is a pure C++ problem, which might be better asked at Stack Overflow. The fact that it is an Arduino is irrelevant to the issue of what you are trying to do with classes and instances of classes.
    – Nick Gammon
    Commented Aug 21, 2019 at 21:40
  • That might be a fair point. I was uncertain, though, if there might be some extra method that Arduino happened to use or implement that might make this easier.
    – user47164
    Commented Aug 27, 2019 at 2:32
  • @RDragonrydr Arduino just uses g++ - the industry-standard compiler (or one of them, anyway). There is no special "Arduino" functionality that you can call on.
    – Nick Gammon
    Commented Aug 28, 2019 at 7:48
  • I was thinking that maybe they overloaded the callback registering function, or some other method that would simplify it. I'm just using the lambdas now, though...
    – user47164
    Commented Sep 20, 2019 at 18:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.