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

Class that is able to perform dynamic dispatch on multiple functions with one parameter. More...

Inheritance diagram for aurora::SingleDispatcher< 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, 1 >::Type UserData
 Addition parameter for user data, only useful if Signature contains more than 1 parameter.
 

Public Member Functions

 SingleDispatcher ()
 Default constructor.
 
 SingleDispatcher (SingleDispatcher &&source)
 Move constructor.
 
SingleDispatcheroperator= (SingleDispatcher &&source)
 Move assignment operator.
 
 ~SingleDispatcher ()
 Destructor.
 
template<typename Id , typename Fn >
void bind (const Id &identifier, Fn function)
 Registers a function bound to a specific key. More...
 
Result call (Parameter arg) const
 Dispatches the key of arg and invokes the corresponding function. More...
 
Result call (Parameter arg, UserData data) const
 Invokes the function depending on arg 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, 1>>
class aurora::SingleDispatcher< Signature, Traits >

Class that is able to perform dynamic dispatch on multiple functions with one parameter.

Sometimes you encounter the situation where you need to implement polymorphic behavior, but you cannot or don't want to add a virtual function to an existing class hierarchy. Here comes dynamic dispatch into play: You define free functions, which can be treated by the dispatcher like virtual functions.

Template Parameters
SignatureFunction signature R(B) or R(B, U), with the following types:
  • B: Reference or pointer to polymorphic class, which is the base class of every dispatched function's parameter type. When B is a pointer, the arguments of the dispatched functions shall be pointers too (the same applies to references). If B is a pointer or reference to const, the dispatched functions cannot modify their arguments. In this case, 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);
// trampoline1() takes a function that is passed to SingleDispatcher::bind() and modifies it in order to fit the common
// R(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 template parameter Id is required, as it will be explicitly specified when trampoline1() is called.
template <typename Id, typename Fn>
static std::function<R(B)> trampoline1(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 func1(Derived1* d);
void func2(Derived2* d);
// Create dispatcher and register functions
dispatcher.bind(aurora::Type<Derived1>(), &func1);
dispatcher.bind(aurora::Type<Derived2>(), &func2);
// Invoke functions on base class pointer
Base* ptr = new Derived1;
dispatcher.call(ptr); // Invokes void func1(Derived1* d);
delete ptr;

Member Function Documentation

template<typename Signature, class Traits = RttiDispatchTraits<Signature, 1>>
template<typename Id , typename Fn >
void aurora::SingleDispatcher< Signature, Traits >::bind ( const Id &  identifier,
Fn  function 
)

Registers a function bound to a specific key.

Template Parameters
IdType that identifies the class. By default, this is aurora::Type<D>, where D is the derived class. Can be deduced from the argument.
FnType of the function. Can be deduced from the argument.
Parameters
identifierValue that identifies the object. The key, which is mapped to the function, is computed from the identifier through Traits::keyFromId(identifier).
functionFunction to register and associate with the given identifier. Usually, the function has the signature Result(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 second parameter for the Signature template parameter, the function should have the signature Result(Parameter, Parameter, UserData).
template<typename Signature, class Traits = RttiDispatchTraits<Signature, 1>>
Result aurora::SingleDispatcher< Signature, Traits >::call ( Parameter  arg) const

Dispatches the key of arg and invokes the corresponding function.

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.

Parameters
argFunction argument as a reference or pointer.
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, 1>>
Result aurora::SingleDispatcher< Signature, Traits >::call ( Parameter  arg,
UserData  data 
) const

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

Dispatches the key of arg and invokes the corresponding function

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.

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

Parameters
argFunction argument as a reference or pointer.
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, 1>>
void aurora::SingleDispatcher< 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, 1>().

Parameters
functionFunction according to the specified signature.

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