0

I want to implement a "service" of callbacks, where subscribers register or unregister a callback. I was thinking about indexing the callbacks by the function address, so that to unregister one would simply have to pass the same function.

So, disregarding threading issues, the simplest form of my implementation would be

#include <functional>
#include <map>
#include <cstdint>

std::map<std::uintptr_t, std::function<void()>> callbacks;

///https://stackoverflow.com/a/18039824/2436175
namespace {
std::uintptr_t get_address(std::function<void()> f) {
    typedef void(function_type)();
    function_type** function_pointer = f.template target<function_type*>();
    return static_cast<std::uintptr_t>(*function_pointer);
}
}// namespace

void subscribe(std::function<void()>&& callback) {
    callbacks.insert(std::make_pair(get_address(callback), std::move(callback)));
}

void unsubscribe(const std::function<void()>& callback) {
    callbacks.erase(get_address(callback));
}

void execute() {
    for (const auto& callback : callbacks) {
       callback.second.operator()();
    }
}

On the subscriber side, we would have things like:

void test() {
}
    
subscribe(test);
unsubscribe(test);

I tested and it would seem to work. See code sample.

Assuming I will only use plain functions like test in this example (no lambdas, no bound methods...), is this a solid mechanism?

Antonio
  • 18,335
  • 12
  • 89
  • 190
  • Why not return a handle (index) from the subscribe function, that can be used to unsubscribe? Using addresses for the purpose of indexing functions would make me a little bit nervous. If you have bound member functions or lambdas with captured variables stored in the `std::function`, there might be different objects with the same function address. Also you cannot subscribe with the same function twice... – Jakob Stark Jun 02 '22 at 15:22
  • @JakobStark I thought about returning an ID upon subscription, but the point of this mechanism would be that the subscriber wouldn't need to keep memory of this ID. It is an important advantage for my use case. The use cases you describe are valid, but are outside my scope... At least for the moment... I think though using `bind` would give me a unique address even for the object and its own version of the function (I might be very wrong though, and if that is the case I would keep a different subscribe method storing also the address of the object to complete the indexing) – Antonio Jun 02 '22 at 15:25
  • @Antonie You see that is a reason why this question is not very well suited for SO. It is opinion based. I would say that this is not a solid mechanism. Others would maybe say the opposite. Both could be right depending on the exact usecase. – Jakob Stark Jun 02 '22 at 15:30
  • @JakobStark Thanks for the observation, I added a statement to constrain the scope of the question. – Antonio Jun 02 '22 at 15:32

0 Answers0