dispatch - acfr/comma GitHub Wiki
Generic wrappers for the double dispatch.
Under the hood it does 2 dynamic casts, but the purpose of this library is not all-beating performance, but convenient semantics.
After all dynamic cast not necessarily is the main performance bottleneck.
// dispatched classes struct fish : public comma::dispatch::dispatched< fish > { /* define methods as usual */ }; struct butterfly : public comma::dispatch::dispatched< butterfly > { /* define methods as usual */ }; // handlers struct fisherman : public dispatch::handler_of< fish > , public dispatch::handler_of< butterfly > { void handle( fish& f ) { std::cerr << " caught a fish" << std::endl; } void handle( butterfly& f ) { std::cerr << " used butterfly as a bait" << std::endl; } }; struct scientist : public dispatch::handler_of< fish > , public dispatch::handler_of< butterfly > { void handle( fish& f ) { std::cerr << " does not care about fish" << std::endl; } void handle( butterfly& f ) { std::cerr << " pinned butterfly in his collection" << std::endl; } }; int main( int ac, char** av ) { comma::dispatch::handler* f = new fisherman; comma::dispatch::handler* s = new scientist; comma::dispatch::dispatched_base* df = new fish; comma::dispatch::dispatched_base* db = new butterfly; std::cerr << std::endl << "fisherman:" << std::endl; df->dispatch_to( f ); db->dispatch_to( f ); std::cerr << std::endl << "scientist:" << std::endl; df->dispatch_to( s ); db->dispatch_to( s ); }
The output will be:
scientist: does not care about fish pinned butterfly in his collection
Suppose, we do not want our classes to be coupled with dispatch::dispatched (e.g. they are legacy classes that we cannot change, but this decoupling is generally a good idea):
Let us start with main() to demonstrate the usage:
int main( int, char** ) { comma::dispatch::handler* h = new hunter; comma::dispatch::handler* s = new soldier; comma::dispatch::dispatched_base* dh = new dispatched< human >; comma::dispatch::dispatched_base* dw = new dispatched< wolf >; comma::dispatch::dispatched_base* ds = new dispatched< star >; std::cerr << std::endl << "hunter:" << std::endl; dh->dispatch_to( h ); dw->dispatch_to( h ); ds->dispatch_to( h ); std::cerr << std::endl << "soldier:" << std::endl; dh->dispatch_to( s ); dw->dispatch_to( s ); ds->dispatch_to( s ); return 0; }
The output will be:
soldier: shot a human said hi to a wolf saw aliens landing
Out type definitions:
Suppose, we do not want the classes human, wolf, and star to be coupled with dispatch::dispatched (e.g. they are legacy classes that we cannot change) defined as following:
struct human {}; struct wolf {}; struct star {};
Now, define a convenience wrapper (we don't have to, but it will make the rest of the code more succinct):
template < typename T > struct dispatched : public comma::dispatch::dispatched< dispatched< T > > , public T {};
Define handlers:
struct soldier : public dispatch::handler_of< dispatched< human > > , public dispatch::handler_of< dispatched< wolf > > , public dispatch::handler_of< dispatched< star > > { void handle( dispatched< human >& h ) { std::cerr << " shot a human" << std::endl; } void handle( dispatched< wolf >& w ) { std::cerr << " said hi to a wolf" << std::endl; } void handle( dispatched< star >& s ) { std::cerr << " saw aliens landing" << std::endl; } };