Prepare the Slot classes to be used independently of Signals Added some polish around them and, to mark this special occasion, moved them out of the SigImpl namespace. PS: This partially reverts commit 0775350fee345e37fb59835dda4d85664346b606, since I had to reintroduce ReturnType template parameter, because it will be used in other places. But Signal classes remain without the ReturnType, because I still cannot imagine how would it be used.
Pavel Labath pavelo@centrum.sk
2 files changed,
117 insertions(+),
64 deletions(-)
M
src/FbTk/Signal.hh
→
src/FbTk/Signal.hh
@@ -22,6 +22,7 @@
#ifndef FBTK_SIGNAL_HH #define FBTK_SIGNAL_HH +#include "RefCount.hh" #include "Slot.hh" #include <algorithm> #include <list>@@ -120,66 +121,90 @@ Trackers m_trackers; ///< all instances that tracks this signal.
unsigned m_emitting; }; -template <typename Arg1, typename Arg2, typename Arg3> -class SignalTemplate: public SignalHolder { +} // namespace SigImpl + + +/// Specialization for three arguments. +template <typename Arg1 = SigImpl::EmptyArg, typename Arg2 = SigImpl::EmptyArg, typename Arg3 = SigImpl::EmptyArg > +class Signal: public SigImpl::SignalHolder { public: - template<typename Functor> - SlotID connect(const Functor& functor) { - return SignalHolder::connect(SlotPtr( new Slot<Arg1, Arg2, Arg3, Functor>(functor) )); - } - -protected: - void emit_(Arg1 arg1, Arg2 arg2, Arg3 arg3) { + void emit(Arg1 arg1, Arg2 arg2, Arg3 arg3) { begin_emitting(); for ( Iterator it = begin(); it != end(); ++it ) { if(*it) - static_cast<SigImpl::SlotTemplate<Arg1, Arg2, Arg3> &>(**it)(arg1, arg2, arg3); + static_cast<Slot<void, Arg1, Arg2, Arg3> &>(**it)(arg1, arg2, arg3); } end_emitting(); } -}; -} // namespace SigImpl - - -/// Base template for three arguments. -template <typename Arg1 = SigImpl::EmptyArg, typename Arg2 = SigImpl::EmptyArg, typename Arg3 = SigImpl::EmptyArg > -class Signal: public SigImpl::SignalTemplate<Arg1, Arg2, Arg3> { -public: - void emit(Arg1 arg1, Arg2 arg2, Arg3 arg3) - { SigImpl::SignalTemplate<Arg1, Arg2, Arg3>::emit_(arg1, arg2, arg3); } + template<typename Functor> + SlotID connect(const Functor& functor) { + return SignalHolder::connect(SlotPtr( + new SlotImpl<Functor, void, Arg1, Arg2, Arg3>(functor) + )); + } }; /// Specialization for two arguments. template <typename Arg1, typename Arg2> -class Signal<Arg1, Arg2, SigImpl::EmptyArg>: - public SigImpl::SignalTemplate<Arg1, Arg2, SigImpl::EmptyArg> { +class Signal<Arg1, Arg2, SigImpl::EmptyArg>: public SigImpl::SignalHolder { public: void emit(Arg1 arg1, Arg2 arg2) { - SigImpl::SignalTemplate<Arg1, Arg2, SigImpl::EmptyArg>:: - emit_(arg1, arg2, SigImpl::EmptyArg()); + begin_emitting(); + for ( Iterator it = begin(); it != end(); ++it ) { + if(*it) + static_cast<Slot<void, Arg1, Arg2> &>(**it)(arg1, arg2); + } + end_emitting(); + } + + template<typename Functor> + SlotID connect(const Functor& functor) { + return SignalHolder::connect(SlotPtr( + new SlotImpl<Functor, void, Arg1, Arg2>(functor) + )); } }; /// Specialization for one argument. template <typename Arg1> -class Signal<Arg1, SigImpl::EmptyArg, SigImpl::EmptyArg>: - public SigImpl::SignalTemplate<Arg1, SigImpl::EmptyArg, SigImpl::EmptyArg> { +class Signal<Arg1, SigImpl::EmptyArg, SigImpl::EmptyArg>: public SigImpl::SignalHolder { public: - void emit(Arg1 arg1) { - SigImpl::SignalTemplate<Arg1, SigImpl::EmptyArg, SigImpl::EmptyArg> - ::emit_(arg1, SigImpl::EmptyArg(), SigImpl::EmptyArg()); + void emit(Arg1 arg) { + begin_emitting(); + for ( Iterator it = begin(); it != end(); ++it ) { + if(*it) + static_cast<Slot<void, Arg1> &>(**it)(arg); + } + end_emitting(); + } + + template<typename Functor> + SlotID connect(const Functor& functor) { + return SignalHolder::connect(SlotPtr( + new SlotImpl<Functor, void, Arg1>(functor) + )); } }; /// Specialization for no arguments. template <> -class Signal<SigImpl::EmptyArg, SigImpl::EmptyArg, SigImpl::EmptyArg>: - public SigImpl::SignalTemplate<SigImpl::EmptyArg, SigImpl::EmptyArg, SigImpl::EmptyArg> { +class Signal<SigImpl::EmptyArg, SigImpl::EmptyArg, SigImpl::EmptyArg>: public SigImpl::SignalHolder { public: void emit() { - SigImpl::SignalTemplate<SigImpl::EmptyArg, SigImpl::EmptyArg, SigImpl::EmptyArg> - ::emit_(SigImpl::EmptyArg(), SigImpl::EmptyArg(), SigImpl::EmptyArg()); + begin_emitting(); + for ( Iterator it = begin(); it != end(); ++it ) { + if(*it) + static_cast<Slot<void> &>(**it)(); + } + end_emitting(); + } + + template<typename Functor> + SlotID connect(const Functor& functor) { + return SignalHolder::connect(SlotPtr( + new SlotImpl<Functor, void>(functor) + )); } };
M
src/FbTk/Slot.hh
→
src/FbTk/Slot.hh
@@ -22,7 +22,7 @@
#ifndef FBTK_SLOT_HH #define FBTK_SLOT_HH -#include "RefCount.hh" +#include "NotCopyable.hh" namespace FbTk {@@ -31,71 +31,99 @@ namespace SigImpl {
struct EmptyArg {}; -class SlotBase { +/** A base class for all slots. It's purpose is to provide a virtual destructor and to enable the + * Signal class to hold a pointer to a generic slot. + */ +class SlotBase: private FbTk::NotCopyable { public: virtual ~SlotBase() {} }; -template<typename Arg1, typename Arg2, typename Arg3> -class SlotTemplate: public SlotBase { +} // namespace SigImpl + +/** Declares a pure virtual function call operator with a specific number of arguments (depending + * on the template specialization). This allows us to "call" any functor in an opaque way. + */ +template<typename ReturnType, typename Arg1 = SigImpl::EmptyArg, + typename Arg2 = SigImpl::EmptyArg, typename Arg3 = SigImpl::EmptyArg> +class Slot: public SigImpl::SlotBase { +public: + virtual ReturnType operator()(Arg1, Arg2, Arg3) = 0; +}; + +/// Specialization for two arguments +template<typename ReturnType, typename Arg1, typename Arg2> +class Slot<ReturnType, Arg1, Arg2, SigImpl::EmptyArg>: public SigImpl::SlotBase { public: - virtual void operator()(Arg1, Arg2, Arg3) = 0; + virtual ReturnType operator()(Arg1, Arg2) = 0; }; -template<typename Arg1, typename Arg2, typename Arg3, typename Functor> -class Slot: public SlotTemplate<Arg1, Arg2, Arg3> { +/// Specialization for one argument +template<typename ReturnType, typename Arg1> +class Slot<ReturnType, Arg1, SigImpl::EmptyArg, SigImpl::EmptyArg>: public SigImpl::SlotBase { public: - virtual void operator()(Arg1 arg1, Arg2 arg2, Arg3 arg3) - { m_functor(arg1, arg2, arg3); } + virtual ReturnType operator()(Arg1) = 0; +}; - Slot(Functor functor) : m_functor(functor) {} +/// Specialization for no arguments +template<typename ReturnType> +class Slot<ReturnType, SigImpl::EmptyArg, SigImpl::EmptyArg, SigImpl::EmptyArg>: public SigImpl::SlotBase { +public: + virtual ReturnType operator()() = 0; +}; + +/** A class which knows how to call a specific functor. It inherits from Slot and implemetents + * the function call operator + */ +template<typename Functor, typename ReturnType, typename Arg1 = SigImpl::EmptyArg, + typename Arg2 = SigImpl::EmptyArg, typename Arg3 = SigImpl::EmptyArg> +class SlotImpl: public Slot<ReturnType, Arg1, Arg2, Arg3> { +public: + virtual ReturnType operator()(Arg1 arg1, Arg2 arg2, Arg3 arg3) + { return m_functor(arg1, arg2, arg3); } + + SlotImpl(Functor functor) : m_functor(functor) {} private: Functor m_functor; }; -// specialization for two arguments -template<typename Arg1, typename Arg2, typename Functor> -class Slot<Arg1, Arg2, EmptyArg, Functor>: public SlotTemplate<Arg1, Arg2, EmptyArg> { +/// Specialization for two arguments +template<typename Functor, typename ReturnType, typename Arg1, typename Arg2> +class SlotImpl<Functor, ReturnType, Arg1, Arg2, SigImpl::EmptyArg>: public Slot<ReturnType, Arg1, Arg2> { public: - virtual void operator()(Arg1 arg1, Arg2 arg2, EmptyArg) - { m_functor(arg1, arg2); } + virtual ReturnType operator()(Arg1 arg1, Arg2 arg2) { return m_functor(arg1, arg2); } - Slot(Functor functor) : m_functor(functor) {} + SlotImpl(Functor functor) : m_functor(functor) {} private: Functor m_functor; }; -// specialization for one argument -template<typename Arg1, typename Functor> -class Slot<Arg1, EmptyArg, EmptyArg, Functor>: public SlotTemplate<Arg1, EmptyArg, EmptyArg> { +/// Specialization for one argument +template<typename Functor, typename ReturnType, typename Arg1> +class SlotImpl<Functor, ReturnType, Arg1, SigImpl::EmptyArg, SigImpl::EmptyArg>: public Slot<ReturnType, Arg1> { public: - virtual void operator()(Arg1 arg1, EmptyArg, EmptyArg) - { m_functor(arg1); } + virtual ReturnType operator()(Arg1 arg1) { return m_functor(arg1); } - Slot(Functor functor) : m_functor(functor) {} + SlotImpl(Functor functor) : m_functor(functor) {} private: Functor m_functor; }; -// specialization for no arguments -template<typename Functor> -class Slot<EmptyArg, EmptyArg, EmptyArg, Functor>: public SlotTemplate<EmptyArg, EmptyArg, EmptyArg> { +/// Specialization for no arguments +template<typename Functor, typename ReturnType> +class SlotImpl<Functor, ReturnType, SigImpl::EmptyArg, SigImpl::EmptyArg, SigImpl::EmptyArg>: public Slot<ReturnType> { public: - virtual void operator()(EmptyArg, EmptyArg, EmptyArg) - { m_functor(); } + virtual ReturnType operator()() { return m_functor(); } - Slot(Functor functor) : m_functor(functor) {} + SlotImpl(Functor functor) : m_functor(functor) {} private: Functor m_functor; }; -} // namespace SigImpl - } // namespace FbTk - #endif // FBTK_SLOT_H