Public Types | Public Member Functions | List of all members
aurora::DoubleDispatcher< Signature, Traits > Class Template Reference

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

Inheritance diagram for aurora::DoubleDispatcher< Signature, Traits >:
Inheritance graph

Public Types

typedef FunctionResult< Signature >::Type Result
 Function return type.
 
typedef FunctionParam< Signature, 0 >::Type Parameter
 Function parameter type denoting the object used for the dispatch.
 
typedef FunctionParam< Signature, 2 >::Type UserData
 Addition parameter for user data, only useful if Signature contains more than 2 parameters.
 

Public Member Functions

 DoubleDispatcher (bool symmetric=true)
 Constructor. More...
 
 DoubleDispatcher (DoubleDispatcher &&source)
 Move constructor.
 
DoubleDispatcheroperator= (DoubleDispatcher &&source)
 Move assignment operator.
 
 ~DoubleDispatcher ()
 Destructor.
 
template<typename Id1 , typename Id2 , typename Fn >
void bind (const Id1 &identifier1, const Id2 &identifier2, Fn function)
 Registers a function bound to a specific key. More...
 
Result call (Parameter arg1, Parameter arg2) const
 Dispatches the key of arg1 and arg2 and invokes the corresponding function. More...
 
Result call (Parameter arg1, Parameter arg2, UserData data) const
 Invokes the function depending on arg1 and arg2 and passes a user-defined argument data. More...
 
void fallback (std::function< Signature > function)
 Registers a fallback function. More...
 

Detailed Description

template<typename Signature, class Traits = RttiDispatchTraits<Signature, 2>>
class aurora::DoubleDispatcher< Signature, Traits >

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
SignatureFunction signature R(B, B)or R(B, B, U), with the following types:
  • B: Reference 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.
  • R: Return type of the dispatched functions.
  • U: Any parameter type that can be used to forward user arguments to the functions
TraitsTraits class to customize the usage of the dispatcher. To define your own traits, you can (but don't have to) inherit the class aurora::DispatchTraits<K>, where K is your key. It predefines most members for convenience. In general, the Traits class must contain the following members:
struct Traits
{
// The type that is used to differentiate objects. For RTTI class hierarchies, std::type_index is a good choice
// -- but you're free to choose anything, such as an enum or a string. The requirements are that Key can be used
// as a key in std::unordered_map, i.e. it must support a std::hash<Key> specialization and operator==.
typedef K Key;
// A function that returns the corresponding key (such as std::type_index) from a type identifier (such as aurora::Type<T>).
// The type identifier is passed to bind() and can contain static type information, while the key is used by the map
// storing the registered functions. Often, key and type identifier are the same.
static Key keyFromId(Id id);
// Given a function argument base, this static function extracts the key from it. B corresponds to the template parameter
// specified at SingleDispatcher, that is, it is a reference or pointer.
static Key keyFromBase(B base);
// trampoline2() takes a function that is passed to DoubleDispatcher::bind() and modifies it in order to fit the common
// R(B, B) signature. It therefore acts as a wrapper for user-defined functions which can link different signatures together.
// For example, this is the place to insert downcasts.
// The first two template parameters Id1 and Id2 are required, as they will be explicitly specified when trampoline2() is called.
template <typename Id1, typename Id2, typename Fn>
static std::function<R(B, B)> trampoline2(Fn f);
// Optional function that returns a string representation of key for debugging.
static const char* name(Key k);
};

Usage example:

// Example class hierarchy
class Base { public: virtual ~Base() {} };
class Derived1 : public Base {};
class Derived2 : public Base {};
// Free functions for the derived types
void func11(Derived1* lhs, Derived1* rhs);
void func12(Derived1* lhs, Derived2* rhs);
void func22(Derived2* lhs, Derived2* rhs);
// Create dispatcher and register functions
// Invoke functions on base class pointer
Base* ptr = new Derived1;
dispatcher.call(ptr, ptr); // Invokes void func11(Derived1* lhs, Derived1* rhs);
delete ptr;

Constructor & Destructor Documentation

template<typename Signature, class Traits = RttiDispatchTraits<Signature, 2>>
aurora::DoubleDispatcher< Signature, Traits >::DoubleDispatcher ( bool  symmetric = true)
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.

Member Function Documentation

template<typename Signature, class Traits = RttiDispatchTraits<Signature, 2>>
template<typename Id1 , typename Id2 , typename Fn >
void aurora::DoubleDispatcher< Signature, Traits >::bind ( const Id1 &  identifier1,
const Id2 &  identifier2,
Fn  function 
)

Registers a function bound to a specific key.

Template Parameters
Id1,Id2Types that identify the argument types. By default, these are aurora::Type<D>, where D is a derived class. Can be deduced from the argument.
FnType of the function. Can be deduced from the argument.
Parameters
identifier1,identifier2Values that identify the object. The key, which is mapped to the function, is computed from each identifier through Traits::keyFromId(identifier).
functionFunction to register and associate with the given identifier. Usually, the function has the signature Result(Parameter, Parameter), but it's possible to deviate from it (e.g. using derived classes), see also the note about trampolines in the Traits classes. In case you specified a third parameter for the Signature template parameter, the function should have the signature Result(Parameter, Parameter, UserData).
template<typename Signature, class Traits = RttiDispatchTraits<Signature, 2>>
Result aurora::DoubleDispatcher< Signature, Traits >::call ( Parameter  arg1,
Parameter  arg2 
) const

Dispatches the key of arg1 and arg2 and invokes the corresponding function.

Traits::keyFromBase(arg) is invoked to determine the key of each passed argument. The function bound to the combination of both keys is then looked up in the map and invoked. If no match is found and a fallback function has been registered using fallback(), then the fallback function will be invoked.

When the dispatcher is configured in symmetric mode (see constructor), then the arguments are forwarded to the correct parameters in the registered functions, even if the order is different. When necessary, they are swapped. In other words, symmetric dispatchers don't care about the order of the arguments at all.

Parameters
arg1,arg2Function arguments as references or pointers.
Returns
The return value of the dispatched function, if any.
Exceptions
FunctionCallExceptionwhen no corresponding function is found and no fallback has been registered.
template<typename Signature, class Traits = RttiDispatchTraits<Signature, 2>>
Result aurora::DoubleDispatcher< Signature, Traits >::call ( Parameter  arg1,
Parameter  arg2,
UserData  data 
) const

Invokes the function depending on arg1 and arg2 and passes a user-defined argument data.

Traits::keyFromBase(arg) is invoked to determine the key of the passed argument. The function bound to that key is then looked up in the map and invoked. If no match is found and a fallback function has been registered using fallback(), then the fallback function will be invoked.

When the dispatcher is configured in symmetric mode (see constructor), then the arguments are forwarded to the correct parameters in the registered functions, even if the order is different. When necessary, they are swapped. In other words, symmetric dispatchers don't care about the order of the first two arguments.

This method is only enabled if the Signature template parameter contains 3 parameters.

Parameters
arg1,arg2Function arguments as references or pointers.
dataAn additional user argument that is forwarded to the function.
Returns
The return value of the dispatched function, if any.
Exceptions
FunctionCallExceptionwhen no corresponding function is found and no fallback has been registered.
template<typename Signature, class Traits = RttiDispatchTraits<Signature, 2>>
void aurora::DoubleDispatcher< Signature, Traits >::fallback ( std::function< Signature >  function)

Registers a fallback function.

The passed function will be invoked when call() doesn't find a registered function. It can be used when not finding a match does not represent an exceptional situation, but a common case.

If you want to perform no action, you can pass aurora::NoOp<R, 2>().

Parameters
functionFunction according to the specified signature.

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