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.

examples

a simple example

 // 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

non-invasive

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; }
 };
⚠️ **GitHub.com Fallback** ⚠️