so I put it into ChatGPT
Seems to make it more complicated than it needs to be. No check in the Handlers if the class pointer is 0, and there is an opportunity for that to happen. A larger than needed set of functions outside the class that have to all be glued together. It also has a task method which is essentially manually calling the callback, which makes the callback not very useful.
Instead, the class instances can be declared for the Handlers to use, and only these Handlers can use the class private interrupt function. If the Encoder instance used in the Handler does not exist the linker will certainly let you know about it (error) and there is then no need to check if a class pointer is null if class pointers were otherwise in use to do this job (and then decide what to do if null). There is also no need for the Encoder class to do anything other than keep track of the encoder count and provide it to anyone that asks for the count value, and the user of the class can deal with the count however it wants. If you want to use a callback in the context of the interrupt, that can be added as done in the example but there is no dependency on it being set and the encoder is tracked regardless.
You still have to manually deal with the interrupt handlers, as they need Encoder instance names to use (as described earlier in this thread, with just a light addition of using operator() so the user does not have to come up with the appropriate class method name to use). But the usage in creating each Encoder instance is only a single line of code which does not require you to 'assemble' various pieces together to make it all work.
https://godbolt.org/z/T649MY6aK