Boost logo

Boost :

Subject: [boost] Request for interest in a library to ease double dispatching
From: Per Karlström (per_at_[hidden])
Date: 2012-12-03 09:13:58


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


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk