I l@ve RuBoard Previous Section Next Section

11.14 Double Dispatcher Quick Facts

  • Loki defines three basic double dispatchers: StaticDispatcher, BasicDispatcher, and BasicFastDispatcher.

  • StaticDispatcher's declaration:

    
    
    template
    
    
    <
    
    
       class Executor,
    
    
       class BaseLhs,
    
    
       class TypesLhs,
    
    
       class BaseRhs = BaseLhs,
    
    
       class TypesRhs = TypesLhs,
    
    
       typename ResultType = void
    
    
    >
    
    
    class StaticDispatcher;
    
    
    

    where

    BaseLhs is the base left-hand type.

    TypesLhs is a typelist containing the set of concrete types involved in the double dispatch on the left-hand side.

    BaseRhs is the base right-hand type.

    TypesRhs is a typelist containing the set of concrete types involved in the double dispatch on the right-hand side.

    Executor is a class that provides the functions to be invoked after type discovery. Executor must provide an overloaded member function Fire for each combination of types in TypesLhs and TypesRhs.

    ResultType is the type returned by the Executor::Fire overloaded functions. The returned value will be forwarded as the result of StaticDispatcher::Go.

  • Executor must provide a member function OnError(BaseLhs&, BaseRhs&) for error handling. StaticDispatcher calls Executor::OnError when it encounters an unknown type.

  • Example (assume Rectangle and Ellipse inherit Shape, and Printer and Screen inherit OutputDevice):

    
    
    struct Painter
    
    
    {
    
    
       bool Fire(Rectangle&, Printer&);
    
    
       bool Fire(Ellipse&, Printer&);
    
    
       bool Fire(Rectangle&, Screen&);
    
    
       bool Fire(Ellipse&, Screen&);
    
    
       bool OnError(Shape&, OutputDevice&);
    
    
    };
    
    
    
    
    
    typedef StaticDispatcher
    
    
    <
    
    
       Painter,
    
    
       Shape,
    
    
       TYPELIST_2(Rectangle, Ellipse),
    
    
       OutputDevice,
    
    
       TYPELIST_2(Printer&, Screen),
    
    
       bool
    
    
    >
    
    
    Dispatcher;
    
    
    
  • StaticDispatcher implements the Go member function, which takes a BaseLhs&, a BaseRhs&, and an Executor&, and executes the dispatch. Example (using the previous definitions):

    
    
    Dispatcher disp;
    
    
    Shape* pSh = ...;
    
    
    OutputDevice* pDev = ...;
    
    
    bool result = disp.Go(*pSh, *pDev);
    
    
    
  • BasicDispatcher and BasicFastDispatcher implement dynamic dispatchers that allow users to add handler functions at runtime.

  • BasicDispatcher finds a handler in logarithmic time. BasicFastDispatcher finds a handler in constant time but requires the user to change the definitions of all dispatched classes.

  • Both classes implement the same interface, illustrated here for BasicDispatcher.

    
    
    template
    
    
    <
    
    
       class BaseLhs,
    
    
       class BaseRhs = BaseLhs,
    
    
       typename ResultType = void,
    
    
       typename CallbackType = ResultType (*)(BaseLhs&, BaseRhs&)
    
    
    >
    
    
    class BasicDispatcher;
    
    
    

    where

    CallbackType is the type of object that handles the dispatch.

    BasicDispatcher and BasicFastDispatcher store and invoke objects of this type.

    All other parameters have the same meaning as for StaticDispatcher.

  • The two dispatchers implement the functions described in Table 11.1.

  • In addition to the three basic dispatchers, Loki also defines two advanced layers: FnDispatcher and FunctorDispatcher. They use one of BasicDispatcher or BasicFastDispatcher as a policy.

  • FnDispatcher and FunctorDispatcher have similar declarations, as shown here.

    
    
    template
    
    
    <
    
    
       class BaseLhs,
    
    
       class BaseRhs = BaseLhs,
    
    
       ResultType = void,
    
    
       template <class To, class From>
    
    
         class CastingPolicy = DynamicCast
    
    
       template <class, class, class, class>
    
    
         class DispatcherBackend = BasicDispatcher
    
    
    >
    
    
    class FnDispatcher;
    
    
    

    where

    BaseLhs and BaseRhs are the base classes of the two hierarchies involved in the double dispatch.

    ResultType is the type returned by the callbacks and the dispatcher.

    CastingPolicy is a class template with two parameters. It must implement a static member function Cast that accepts a reference to From and returns a reference to To. The stock implementations DynamicCaster and StaticCaster use dynamic_cast and static_cast, respectively.

    DispatcherBackend is a class template that implements the same interface as BasicDispatcher and BasicFastDispatcher, described in Table 11.1.

  • Both FnDispatcher and FunctorDispatcher provide an Add member function or their primitive handler type. For FnDispatcher the primitive handler type is ResultType (*)(BaseLhs&, BaseRhs&). For FunctorDispatcher, the primitive handler type is Functor<ResultType, TYPELIST_2(BaseLhs&, Base Rhs&)>. Refer to Chapter 5 for a description of Functor.

  • In addition, FnDispatcher provides a template function to register callbacks with the engine:

    
    
    void Add<SomeLhs, SomeRhs,
    
    
       ResultType (*callback)(SomeLhs&, SomeRhs&),
    
    
       bool symmetric>();
    
    
    
  • If you register handlers with the Add member function shown in the previous code, you benefit from automated casting and optional symmetry.

  • FunctorDispatcher provides a template Add member function:

    
    
    template <class SomeLhs, class SomeRhs, class F>
    
    
    void Add(const F& fun);
    
    
    
  • F can be any of the types accepted by the Functor object (see Chapter 5), including another Functor instantiation. An object of type F must accept the function-call operator with arguments of types BaseLhs& and BaseRhs& and return a type convertible to ResultType.

  • If no handler is found, all dispatch engines throw an exception of type std::runtime_error.

    I l@ve RuBoard Previous Section Next Section