http://www.developer.com/tech/article.php/3574276/Examples-in-Event-Dispatching.htm
This is the last article [1] in a series describing possible implementations of a type safe event dispatching mechanism in the context of single-layered and multilayered dispatchers/receptors. This time, you'll learn how dispatchers can be stacked in layers and how events can be selectively sent to certain levels only or broadcasted. Two illustrative implementations are presented: a basic one introducing the main concepts, later refactored in a more refined implementation. In the previous article, I introduced the concept of single-layered ED (Event Dispatcher) as opposed to multilayered ED: "We will call an ED single-layered if between the Source of the Event and the final Receiver there is no Global Relay (in other words, if an event can be solved in the chains directly linked to the source). Otherwise, the ED is multilayered." The following diagram exemplifies the multilayered model: A multilayered system might have event sources possible at every level. Every layer hosts a relay (exceptionally more than one). The relay layout can be composed at runtime so that an event can circulate between relays in a certain flow. Every relay consumes events by further dispatching them to one or more Dispatchers (the Dispatcher/Receptor part was presented in the previous article). If the event is unknown, it is relayed to the next layer, if any, or the compiler detects the missing receptor. The above architectural model serves well in cases when a high level of decoupling is needed. Relays are the single points of contact between modules, relieving modules from sending messages directly from one to another. On top of this, due to the type safe implementation, there is no price to pay for additional indirection/casting and the speed of execution is unaffected. Due to the similarity of Global and Local Relays, the implementation is almost the same as in [1], with two small cosmetic changes: This time Relay::relay is static no more and one Dispatcher/Relay (Basic) no longer inherits from Relay. The difference is in how Relays are handled: Please note how the Relays are indexed and chained. A helper function (RelayGenerator1::relay) allows event dispatching to start from a user-specified level. For example, RelayGenerator1::relay<1> excludes both EvtC and EvtD. A more sophisticated example is presented in the next code excerpt: The first observation is that RG was factored out using RGBase. The second and more important observation is that a broadcast method was implemented. As mentioned in Note 2, broadcast is automatically achieved by dispatching to the last Relay of the chain. A method of automatically finding the last specialization of a Relay (isValidRG) is based on the SFINAE (Substitution Failure Is Not An Error [2]) concept and the remark that RG::DISPATCHER is a class for all the cases when RG is a specialization and otherwise not. I presented two multilayered Event Dispatching implementations, together with a design overview. Single- and multilayered designs were compared and their complementary was underlined. With minimal effort, the reader can either combine the two approaches or use one at a time only. You can download the code that accompanies this article here.
Examples in Event Dispatching
December 30, 2005
The Layered Approach Revisited

Some scenarios:
Notes:
The Multilayered Approach: Implementation
template <class D>
struct Relay
{
Relay(const D& d) : d_(d)
{}
template<class E>
void relay(const E& e)
{
d_.relay(e);
}
private:
D d_;
};
struct EvtA
{
EvtA(char c) : e(c){}
char e;
};
struct EvtB
{
EvtB(char c) : e(c) {}
char e;
};
struct EvtC
{
EvtC(char c) : e(c) {}
char e;
};
struct EvtD
{
EvtD(char c) : e(c) {}
char e;
};
struct BasicLayerDispatcher
{
void relay(const EvtA& e)
{
std::cout << "BasicLayer: " << e.e <<std::endl;
}
};
template <class R>
struct SecondLayerDispatcher : public Relay<R>
{
SecondLayerDispatcher(const R& r) : Relay<R>(r){}
using Relay<R>::relay;
void relay(const EvtB& e)
{
std::cout << "2ndLayer: " << e.e <<std::endl;
}
};
template <class R>
struct ThirdLayerDispatcher : public Relay<R>
{
ThirdLayerDispatcher(const R& r) : Relay<R>(r){}
using Relay<R>::relay;
void relay((const EvtC& e)
{
std::cout << "3rdLayer: " << e.e <<std::endl;
}
void relay(const EvtD& e)
{
std::cout << "3rdLayer: " << e.e <<std::endl;
}
};
namespace RelayGenerator1
{
template <int I>
struct RG
{};
template <>
struct RG<0>
{
typedef BasicLayerDispatcher DISPATCHER;
typedef Relay<DISPATCHER> RELAY;
static RELAY getRelay()
{
return RELAY(DISPATCHER());
}
};
template <>
struct RG<1>
{
typedef SecondLayerDispatcher< RG<0>::RELAY > DISPATCHER;
typedef Relay<DISPATCHER > RELAY;
static RELAY getRelay()
{
return RELAY(DISPATCHER(RG<0>::getRelay()));
}
};
template <>
struct RG<2>
{
typedef ThirdLayerDispatcher< RG<1>::RELAY > DISPATCHER;
typedef Relay<DISPATCHER > RELAY;
static RELAY getRelay()
{
return RELAY(DISPATCHER(RG<1>::getRelay()));
}
};
template <int L, class E>
void relay(const E& e)
{
RG<L>::getRelay().relay(e);
}
}
void action()
{
EvtD e('w');
RelayGenerator1::relay<2>(e);
}
The Refinement
namespace RelayGenerator2
{
template <class R, template <class T> class D = Relay>
struct RGBase
{
typedef D< typename R::RELAY > DISPATCHER;
typedef Relay<DISPATCHER > RELAY;
static RELAY getRelay()
{
return RELAY(DISPATCHER(R::getRelay()));
}
};
template <class R >
struct RGBase<R, Relay>
{
typedef R DISPATCHER;
typedef Relay<DISPATCHER > RELAY;
static RELAY getRelay()
{
return RELAY(R());
}
};
template <int I>
struct RG
{
typedef void DISPATCHER;
};
template <>
struct RG<0> : RGBase<BasicLayerDispatcher>
{ };
template <>
struct RG<1> : RGBase<RG<0>, SecondLayerDispatcher >
{ };
template <>
struct RG<2> : RGBase< RG<1>, ThirdLayerDispatcher>
{};
template <int L, class E>
void relay(const E& e)
{
RG<L>::getRelay().relay(e);
}
template <int I>
struct IsValidRG
{
typedef char ONE;
typedef struct {char a[2];} TWO;
template <class C>
static ONE isClass(...);
template <class C>
static TWO isClass(int C::*);
enum E {
e=sizeof(isClass<typename RG<I>::DISPATCHER>(0) )
== 2 ? IsValidRG<I+1>::e : I-1
};
};
template <>
struct IsValidRG<200>
{
enum E {
e
};
};
template <class E>
void broadcast(const E& e)
{
relay<IsValidRG<0>::e>(e);
}
void action()
{
}
Where You Are
Download the Code
References
Nicolai M. Josuttis. Addison-Wesley, 2002