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?
std::function
s, or only those that reference a pointer to plain function? It's worth stating any limitations. \$\endgroup\$std::function
does quite a bit of adapting on assignment. \$\endgroup\$