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 0775350fee
, 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.
This commit is contained in:
parent
0a40d1caf3
commit
7bca844581
2 changed files with 149 additions and 96 deletions
|
@ -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 @@ private:
|
|||
unsigned m_emitting;
|
||||
};
|
||||
|
||||
template <typename Arg1, typename Arg2, typename Arg3>
|
||||
class SignalTemplate: public 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) {
|
||||
begin_emitting();
|
||||
for ( Iterator it = begin(); it != end(); ++it ) {
|
||||
if(*it)
|
||||
static_cast<SigImpl::SlotTemplate<Arg1, Arg2, Arg3> &>(**it)(arg1, arg2, arg3);
|
||||
}
|
||||
end_emitting();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace SigImpl
|
||||
|
||||
|
||||
/// Base template for three arguments.
|
||||
/// Specialization for three arguments.
|
||||
template <typename Arg1 = SigImpl::EmptyArg, typename Arg2 = SigImpl::EmptyArg, typename Arg3 = SigImpl::EmptyArg >
|
||||
class Signal: public SigImpl::SignalTemplate<Arg1, Arg2, Arg3> {
|
||||
class Signal: public SigImpl::SignalHolder {
|
||||
public:
|
||||
void emit(Arg1 arg1, Arg2 arg2, Arg3 arg3)
|
||||
{ SigImpl::SignalTemplate<Arg1, Arg2, Arg3>::emit_(arg1, arg2, arg3); }
|
||||
void emit(Arg1 arg1, Arg2 arg2, Arg3 arg3) {
|
||||
begin_emitting();
|
||||
for ( Iterator it = begin(); it != end(); ++it ) {
|
||||
if(*it)
|
||||
static_cast<Slot<void, Arg1, Arg2, Arg3> &>(**it)(arg1, arg2, arg3);
|
||||
}
|
||||
end_emitting();
|
||||
}
|
||||
|
||||
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)
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
148
src/FbTk/Slot.hh
148
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 {
|
||||
public:
|
||||
virtual void operator()(Arg1, Arg2, Arg3) = 0;
|
||||
};
|
||||
|
||||
template<typename Arg1, typename Arg2, typename Arg3, typename Functor>
|
||||
class Slot: public SlotTemplate<Arg1, Arg2, Arg3> {
|
||||
public:
|
||||
virtual void operator()(Arg1 arg1, Arg2 arg2, Arg3 arg3)
|
||||
{ m_functor(arg1, arg2, arg3); }
|
||||
|
||||
Slot(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> {
|
||||
public:
|
||||
virtual void operator()(Arg1 arg1, Arg2 arg2, EmptyArg)
|
||||
{ m_functor(arg1, arg2); }
|
||||
|
||||
Slot(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> {
|
||||
public:
|
||||
virtual void operator()(Arg1 arg1, EmptyArg, EmptyArg)
|
||||
{ m_functor(arg1); }
|
||||
|
||||
Slot(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> {
|
||||
public:
|
||||
virtual void operator()(EmptyArg, EmptyArg, EmptyArg)
|
||||
{ m_functor(); }
|
||||
|
||||
Slot(Functor functor) : m_functor(functor) {}
|
||||
|
||||
private:
|
||||
Functor m_functor;
|
||||
};
|
||||
|
||||
} // 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 ReturnType operator()(Arg1, Arg2) = 0;
|
||||
};
|
||||
|
||||
/// Specialization for one argument
|
||||
template<typename ReturnType, typename Arg1>
|
||||
class Slot<ReturnType, Arg1, SigImpl::EmptyArg, SigImpl::EmptyArg>: public SigImpl::SlotBase {
|
||||
public:
|
||||
virtual ReturnType operator()(Arg1) = 0;
|
||||
};
|
||||
|
||||
/// 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 Functor, typename ReturnType, typename Arg1, typename Arg2>
|
||||
class SlotImpl<Functor, ReturnType, Arg1, Arg2, SigImpl::EmptyArg>: public Slot<ReturnType, Arg1, Arg2> {
|
||||
public:
|
||||
virtual ReturnType operator()(Arg1 arg1, Arg2 arg2) { return m_functor(arg1, arg2); }
|
||||
|
||||
SlotImpl(Functor functor) : m_functor(functor) {}
|
||||
|
||||
private:
|
||||
Functor m_functor;
|
||||
};
|
||||
|
||||
/// 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 ReturnType operator()(Arg1 arg1) { return m_functor(arg1); }
|
||||
|
||||
SlotImpl(Functor functor) : m_functor(functor) {}
|
||||
|
||||
private:
|
||||
Functor m_functor;
|
||||
};
|
||||
|
||||
/// Specialization for no arguments
|
||||
template<typename Functor, typename ReturnType>
|
||||
class SlotImpl<Functor, ReturnType, SigImpl::EmptyArg, SigImpl::EmptyArg, SigImpl::EmptyArg>: public Slot<ReturnType> {
|
||||
public:
|
||||
virtual ReturnType operator()() { return m_functor(); }
|
||||
|
||||
SlotImpl(Functor functor) : m_functor(functor) {}
|
||||
|
||||
private:
|
||||
Functor m_functor;
|
||||
};
|
||||
|
||||
} // namespace FbTk
|
||||
|
||||
|
||||
#endif // FBTK_SLOT_H
|
||||
|
|
Loading…
Reference in a new issue