
On 12/03/12 08:13, Per Karlström wrote:
Hi,
I have been tinkering on a template library to ease the use of double dispatching. Now I know there are other techniques such as visitor patterns that might solve this problem in a more general way. However I believe that there are occasions when using double dispatch is a good way forward. I have some excerpts of example code at the end of this mail.
Of course if I somehow have missed a boost library that already handles this I would be happy to know about it.
So if there is even any interest for this I would be happy if someone would like to cooperate with me to make this library better and in the end so good so that it can be part of boost. I feel I do not have the time to spare to finalize this on my own, plus I feel I still have things to learn and would be happy to cooperate with someone more experienced in template programming.
What I in that case need help with is:
*How (or is it) possible to make the library more transparent to the number of types that should be in the double dispatch hierarchy. Right now, as I have shown in the code at the end of this mail, you have to put a post-fix number telling how many types to use.
*How (if possible) can a class be double dispatchable with different return types. The way I solved it was with a union. But would it somehow be possible to do like this
struct Val : public DoubleDispatchable<bool,A,B>, public DoubleDispatchable<int,A,B>
*What else would be needed to start the journey to make this a library fit for boost (is it even good enough to ever make into boost?)
If anyone is interested in a cooperation I am happy to provide my working draft of this library and to have a more private talk about how we could move forward.
Best Regards Per Karlström
For now a union is used to hold the return value to make this simmilar for all types of returns. union ReturnVal { float float_type_m; bool bool_type_m;
ReturnVal(const bool& bool_type_):bool_type_m(bool_type_){} ReturnVal(const float& float_type_):float_type_m(float_type_){} ReturnVal():bool_type_m(false){} };
In essence a library user can define handler classes akin to this:
struct less : public DoubleDispatchHandler_3<ReturnVal,A,B,C> { return_type handle_alpha_alpha(const alpha_type& arg1, const alpha_type& arg2) const {return arg1 < arg2} return_type handle_alpha_beta (const alpha_type& arg1, const beta_type& arg2) const {return true;}
return_type handle_alpha_gamma (const alpha_type& arg1, const gamma_type& arg2) const {return true;}
//And all other combinations };
Or with a default function
struct equal : public DoubleDispatchHandler_3<ReturnVal,A,B,C> { return_type handle_default() const {return false;} return_type handle_alpha_alpha(const alpha_type& arg1, const alpha_type& arg2) const; return_type handle_beta_beta (const beta_type& arg1, const beta_type& arg2) const; return_type handle_gamma_gamma (const gamma_type& arg1, const gamma_type& arg2) const; };
Then the base class is derived from DoubleDispatchable
class Val : public DoubleDispatchable_3<ReturnVal,A,B,C> { public: virtual ~Val(){} virtual std::ostream& print(std::ostream& ost) const=0; virtual bool operator<(const Val& other) const =0; virtual bool operator==(const Val& other) const =0; virtual float combine(const Val& other) const =0; };
While Child classes had to define the member function dispatch_<type> struct A : public Val { int val_m; private: //Handles the first double dispatch call return_type dispatch_alpha(const alpha_type& alpha, const handler_type& handler) const { return double_dispatch(alpha,*this,handler); } return_type dispatch_beta(const beta_type& beta, const handler_type& handler) const { return double_dispatch(beta,*this,handler); } return_type dispatch_gamma(const gamma_type& gamma, const handler_type& handler) const { return double_dispatch(gamma,*this,handler); } public: A(const int& val_=0):val_m(val_){}
//Normal calls to the operators via a template function bool operator<(const Val& other) const { return double_dispatch(*this,other,less()).bool_type_m; }
bool operator==(const Val& other) const { return double_dispatch(*this,other,equal()).bool_type_m; }
float combine(const Val& other) const { return double_dispatch(*this,other,add()).float_type_m; }
std::ostream& print(std::ostream& ost) const { ost<<"A("<<val_m<<")"; return ost; } };
class B{...}; class C{...};
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
There's multiple dispatch code here: http://svn.boost.org/svn/boost/sandbox/variadic_templates/libs/composite_sto... The predator_prey.cpp uses virtual functions for dispatching. The one_of_multiple_dispatch.test.cpp uses either virtual functions or switches to do the dispatching. Unfortunately, I found the timing was pretty slow on the one_of_multiple_dispatch vs. the variant visitor :( HTH. -regards, Larry