Recently, I found myself frequently writing notification managing facilities. That is, one can register as a receiver by providing a callback, and another can send a notification to all registrants by invoking their corresponding callbacks. I had been bothered by re-writing this similar code again and again. Finally, I decided to write a generic one once and for all. Following is the version for cases where the maximum number of registrants is known and limited. So I don't bother using advanced data structures for managing the registered callbacks. Comments pertaining to any aspect of the code are welcome :)
#include <array>
#include <functional>
#include <mutex>
#include <stdexcept>
#include <utility>
template <typename Sig, int max_reg = 16, typename Func = std::function<Sig>>
class NotifyRegistry;
template <int max_reg, typename Func, typename R, typename... Args>
class NotifyRegistry<R(Args...), max_reg, Func>
{
static_assert(max_reg > 0, "");
public:
template <typename F>
int Register(F&& f) {
std::lock_guard<std::mutex> lock(mut_);
int i = -1;
while (++i < max_reg && reg_[i]);
if (i == max_reg) throw std::length_error("");
reg_[i] = std::forward<F>(f);
return i;
}
void Unregister(int id) {
if (id < 0 || id >= max_reg) throw std::invalid_argument("");
std::lock_guard<std::mutex> lock(mut_);
reg_[id] = nullptr;
}
void Notify(Args... args) const {
std::lock_guard<std::mutex> lock(mut_);
for (auto& f : reg_) {
if (f) (void)f(std::forward<Args>(args)...);
}
}
private:
std::array<Func, max_reg> reg_;
mutable std::mutex mut_;
};
if (f) (void)f(std::forward<Args>(args)...);
. Why you need add a(void)
here? \$\endgroup\$