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; }
};