Bromeon
Public Member Functions
thor::DoubleDispatcher< B, R > Class Template Reference

Class that is able to perform dynamic dispatch on multiple functions with two parameters. More...

Inheritance diagram for thor::DoubleDispatcher< B, R >:
Inheritance graph

List of all members.

Public Member Functions

 DoubleDispatcher (bool symmetric=true, bool supportDerivedToBase=false)
 Constructor.
template<class D1 , class D2 >
void Register (R(*globalFunction)(D1#, D2#))
 Registers a global function.
template<class D1 , class D2 , class C >
void Register (R(C::*memberFunction)(D1#, D2#), C &object)
 Registers a member function.
template<class D1 , class D2 , typename Fn >
void Register (const Fn &functionObject)
 Registers a function object.
Call (B arg1, B arg2) const
 Dispatches the dynamic types of arg1 and arg2 and invokes the corresponding function.

Detailed Description

template<class B, typename R = void>
class thor::DoubleDispatcher< B, R >

Class that is able to perform dynamic dispatch on multiple functions with two parameters.

Sometimes you encounter the situation where you need to implement polymorphic behavior to dispatch dynamically on more than one type. Like overloading functions with two parameters at compile time, this class allows you to perform a dispatch on two arguments at runtime. At invocation time, all you need is the static type of the base class, the DoubleDispatcher figures out which dynamic types match which function.

Template Parameters:
BReference or pointer to polymorphic base class. This is the base class of every dispatched function's parameter type. When it is a pointer, the arguments of the dispatched functions shall be pointers too (the same applies to references). the dispatched functions shall have arguments of type pointer or reference to const, too.
RReturn type of the dispatched functions.
 // Example class hierarchy
 class Base { public: virtual ~Base() {} };
 class Derived1 : public Base {};
 class Derived2 : public Base {};

 // Free functions for the derived types
 void Func(Derived1* lhs, Derived1* rhs);
 void Func(Derived1* lhs, Derived2* rhs);
 void Func(Derived2* lhs, Derived2* rhs);

 // Create dispatcher and register functions
 thor::DoubleDispatcher<Base*> dispatcher;
 dispatcher.Register<Derived1, Derived1>(&Func);
 dispatcher.Register<Derived1, Derived2>(&Func);
 dispatcher.Register<Derived2, Derived2>(&Func);

 // Invoke functions on base class pointer
 Base* ptr = new Derived1;
 dispatcher.Call(ptr, ptr); // Invokes void Func(Derived1* lhs, Derived1* rhs);
 delete ptr;

Constructor & Destructor Documentation

template<class B, typename R = void>
thor::DoubleDispatcher< B, R >::DoubleDispatcher ( bool  symmetric = true,
bool  supportDerivedToBase = false 
) [explicit]

Constructor.

Parameters:
symmetricIs true if the calls fn(a,b) and fn(b,a) are equivalent and it's enough to register one of both variants. Otherwise, both calls have to be registered separately and are resolved to different functions.
supportDerivedToBaseSpecifies whether derived-to-base conversions are supported. If no function for a derived class is found, the dispatcher will look for functions taking base class parameters and upcast the arguments, if possible. You need to register the class hierarchy using the macros in Rtti.hpp. On average, calls with derived-to-base conversions are as fast as direct matches, but this feature requires a small memory overhead.

Member Function Documentation

template<class B, typename R = void>
R thor::DoubleDispatcher< B, R >::Call ( arg1,
arg2 
) const

Dispatches the dynamic types of arg1 and arg2 and invokes the corresponding function.

Note that the argument's dynamic type must match exactly with the registered type, unless you enabled derived-to-base conversions in the constructor and specified the class hierarchy. In the latter case, the function with the best match is chosen for overload resolution.

Parameters:
arg1First function argument.
arg2Second function argument.
Returns:
The return value of the dispatched function, if any.
Exceptions:
FunctionCallExceptionwhen no corresponding function is found, or if a call is ambiguous. Ambiguity emerges at derived-to-base conversions if multiple functions represent an equally good match for overload resolution.
template<class B, typename R = void>
template<class D1 , class D2 >
void thor::DoubleDispatcher< B, R >::Register ( R(*)(D1#, D2#)  globalFunction)

Registers a global function.

Template Parameters:
D1Type of the derived class for the first parameter. Must be explicitly specified.
D2Type of the derived class for the second parameter. Must be explicitly specified.
Parameters:
globalFunctionPointer to function to register.

Note that # is a placeholder for either & or *. The types D1# and D2# have the same attributes as B (pointer, reference, const-qualification): For instance, B=const Base& implies D1#=const Derived1&.
Example (class hierarchy and dispatcher declaration missing):

 // Overloaded global or namespace-level functions
 void Func(Derived1&, Derived1&);
 void Func(Derived1&, Derived2&);
 void Func(Derived2&, Derived2&);

 // Register functions
 dispatcher.Register<Derived1, Derived1>(&Func);
 dispatcher.Register<Derived1, Derived2>(&Func);
 dispatcher.Register<Derived2, Derived2>(&Func);
Precondition:
A function taking two arguments of dynamic type D1 and D2 is not registered yet.
template<class B, typename R = void>
template<class D1 , class D2 , class C >
void thor::DoubleDispatcher< B, R >::Register ( R(C::*)(D1#, D2#)  memberFunction,
C &  object 
)

Registers a member function.

Template Parameters:
D1Type of the derived class for the first parameter. Must be explicitly specified.
D2Type of the derived class for the second parameter. Must be explicitly specified.
CClass that holds the member function.
Parameters:
memberFunctionPointer to member function to register.
objectReference to object on which the member function is invoked.

Note that # is a placeholder for either & or *. The types D1# and D2# have the same attributes as B (pointer, reference, const-qualification): For instance, B=const Base& implies D1#=const Derived1&.
Example (class hierarchy and dispatcher declaration missing):

 // Class with overloaded member functions
 struct MyClass
 {
     void MemFunc(Derived1&, Derived1&);
     void MemFunc(Derived1&, Derived2&);
     void MemFunc(Derived2&, Derived2&);
 } obj;

 // Register member functions
 dispatcher.Register<Derived1, Derived1>(&MyClass::MemFunc, obj);
 dispatcher.Register<Derived1, Derived2>(&MyClass::MemFunc, obj);
 dispatcher.Register<Derived2, Derived2>(&MyClass::MemFunc, obj);
Precondition:
A function taking two arguments of dynamic type D1 and D2 is not registered yet.
template<class B, typename R = void>
template<class D1 , class D2 , typename Fn >
void thor::DoubleDispatcher< B, R >::Register ( const Fn &  functionObject)

Registers a function object.

Template Parameters:
D1Type of the derived class for the first parameter. Must be explicitly specified.
D2Type of the derived class for the second parameter. Must be explicitly specified.
FnType of the function object. Can be deduced from the argument.
Parameters:
functionObjectFunctor to register.

Incomplete example using a function object (you can also have separate functors for each function):

 // Class for function objects
 struct Functor
 {
    void operator() (Derived1&, Derived1&);
    void operator() (Derived1&, Derived2&);
    void operator() (Derived2&, Derived2&);
 };

 // Register functor
 dispatcher.Register<Derived1, Derived1>(Functor());
 dispatcher.Register<Derived1, Derived2>(Functor());
 dispatcher.Register<Derived2, Derived2>(Functor());
Precondition:
A function taking two arguments of dynamic type D1 and D2 is not registered yet.

The documentation for this class was generated from the following file: