Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2003-01-12 10:39:15


Toon Knapen <toon.knapen_at_[hidden]> writes:

> I've been looking through some real code to see where we pactically could
> benefit from MPL and think I've found a nice one :
>
> If one wants to integrate generic programming inside a strong OO designed
> program, you might want to try to downcast a pointer to a base-class to all
> possible derived-classes and once you found the right derived class (and got
> all the type information you need again) you can restart using templates and
> a real generic approach. However to do this 'trick ' in a scalable manner,
> you need to try all downcasts based on a compile-time list of all derived
> classes instead of hardcoding the list like :
>
> downcast(base_class* base) {
> derived1 d1 = dynamic_cast< derived1* >( base ) ;
> if ( d1 ) foo< derived1 >( d1 ) ;
>
> derived2 d2 = dynamic_cast< derived2* >( base ) ;
> if ( d2 ) foo< derived2 >( d2 ) ;
> }
>
> This might seem like bad design but is a very helpfull construct to avoid
> performance penalties from a to much OO oriented approach by implementing
> performance critical pieces using generic programming. Therefor I think it
> can appeal to many people that are coming from OO and start looking at
> generic programming.

Hmm, I wouldn't do it that way, though.

     template <class Base>
     struct dispatch_table
          : std::map<boost::python::type_info, void(*)(Base*)> {};

     dispatch_table<base_class> dispatch;

     dispatch[typeid(*base)](base); // invocation

would form the core of my solution.

Then I would add:

     template <class Base, class Operator>
     struct registrar
     {
          registrar(dispatch_table<Base>& table)
            : table(table)
            {}

          template <class Derived>
          void operator()(Derived*)
          {
              table[typeid(Derived)] = &normalize<Derived>::execute;
          }

      private:
          template <class Derived>
          struct normalize
          {
              typedef typename Operator::apply<Derived> derived_op;

              static void execute(Base* base)
              {
                  derived_op::execute(dynamic_cast<Derived*>(base));
              };
          };

          dispatch_table<Base>& table;
     };

And finally:

    struct do_foo
    {
        template <class Derived>
        struct apply
        {
             void execute(Derived* p) { foo<Derived>(p); }
        };
    };

    mpl::for_each< list<leaf1,leaf2,leaf3>, add_pointer<mpl::_> >(
            registrar<base_class,do_foo>(dispatch)
        );

Something like this might make a nice introductory example.

-- 
                       David Abrahams
   dave_at_[hidden] * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution

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