From 5a0963274b2f21590fc72610ff49bba33145d161 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Mon, 28 Sep 2015 17:12:32 +0200 Subject: Completely rewrite Notifier to work with gcc-5.2. Greatly inspired by the lsignal project. --- plugingui/notifier.h | 120 ++++++++++++++++++++++++++++----------------------- 1 file changed, 65 insertions(+), 55 deletions(-) (limited to 'plugingui/notifier.h') diff --git a/plugingui/notifier.h b/plugingui/notifier.h index a9f8831..160fe4e 100644 --- a/plugingui/notifier.h +++ b/plugingui/notifier.h @@ -26,13 +26,51 @@ */ #pragma once -#include #include #include #include #include -#include -#include +#include + +namespace aux +{ + template + struct placeholder + { + }; +} + +namespace std +{ + template + struct is_placeholder> + : integral_constant + { + }; +} + +namespace aux +{ + // std::integer_sequence introduced in C++14 so remove this once we start requiring that. + + template + struct int_sequence + { + }; + + template + struct gen_int_sequence + : gen_int_sequence + { + }; + + template + struct gen_int_sequence<0, Ns...> + : int_sequence + { + }; +}; + namespace GUI { @@ -61,6 +99,7 @@ public: signals.erase(signal); } +private: std::set signals; }; @@ -68,6 +107,8 @@ template class Notifier : public NotifierBase { public: Notifier() {} + + //! \brief When dtor is called it will automatically disconnect all its listeners. ~Notifier() { for(auto slot = slots.begin(); slot != slots.end(); ++slot) { @@ -75,19 +116,26 @@ public: } } - void connect(Listener* object, std::function slot) + using callback_type = std::function; + + //! \brief Connect object to this Notifier. + template + void connect(O* p, const F& fn) { - slots[object] = slot; - if(object) { - object->registerNotifier(this); + slots[p] = std::move(construct_mem_fn(fn, p, aux::gen_int_sequence{})); + if(p && dynamic_cast(p)) { + dynamic_cast(p)->registerNotifier(this); } } + //! \brief Disconnect object from this Notifier. void disconnect(Listener* object) { slots.erase(object); } + //! \brief Activate this notifier by pretending it is a function. + //! Example: Notifier foo; foo(42); void operator()(Args... args) { for(auto slot = slots.begin(); slot != slots.end(); ++slot) { @@ -95,55 +143,17 @@ public: } } - std::map> slots; -}; - -} // GUI:: - -template struct seq{}; -template -struct gen_seq : gen_seq{}; -template -struct gen_seq<0, Is...> : seq{}; - -template struct placeholder{}; - -namespace std{ -template -struct is_placeholder< ::placeholder > : integral_constant{}; -} // std:: - -namespace aux{ -template -auto easy_bind(seq, F&& f, Ts&&... vs) - -> decltype(std::bind(std::forward(f), std::forward(vs)..., ::placeholder<1 + Is>()...)) -{ - return std::bind(std::forward(f), std::forward(vs)..., ::placeholder<1 + Is>()...); -} -} // aux:: +private: + std::map slots; -template -auto mem_bind(R (C::*ptmf)(FArgs...), Args&&... vs) - -> decltype(aux::easy_bind(gen_seq<(sizeof...(FArgs) + 1) - sizeof...(Args)>(), ptmf, std::forward(vs)...)) -{ - // the +1s for 'this' argument - static_assert(sizeof...(Args) <= sizeof...(FArgs) + 1, "too many arguments to mem_bind"); - return aux::easy_bind(gen_seq<(sizeof...(FArgs) + 1) - sizeof...(Args)>(), ptmf, std::forward(vs)...); -} - -template -auto mem_bind(T C::*ptmd, Args&&... vs) - -> decltype(aux::easy_bind(gen_seq<1 - sizeof...(Args)>(), ptmd, std::forward(vs)...)) -{ - // just 'this' argument - static_assert(sizeof...(Args) <= 1, "too many arguments to mem_bind"); - return aux::easy_bind(gen_seq<1 - sizeof...(Args)>(), ptmd, std::forward(vs)...); -} + template + callback_type construct_mem_fn(const F& fn, O* p, aux::int_sequence) const + { + return std::bind(fn, p, aux::placeholder{}...); + } -//#define obj_connect_old(SRC, SIG, TAR, SLO) (SRC).SIG.connect(&(TAR), mem_bind(&decltype(TAR)::SLO, TAR)) +}; -#define fun_connect(SRC, SIG, SLO) \ - (SRC).SIG.connect(nullptr, SLO) +} // GUI:: -#define obj_connect(SRC, SIG, TAR, SLO) \ - (SRC)->SIG.connect(TAR, mem_bind(&SLO, std::ref(*TAR))) +#define CONNECT(SRC, SIG, TAR, SLO) SRC->SIG.connect(TAR, SLO) -- cgit v1.2.3