I have a class with a state machine, and want to have a single point of entry to pass events to the state machine. The event is accompanied with event specific data, which I then want to dispatch to handlers. So it looks something like this...
class X
{
public:
...
template<typename... A> void fsm(eEvent eventId, const A&... eventData);
private:
...
void eventA(int a, double b);
void eventB(std::string a);
void eventC(unsigned long a);
};
...with invocations that look like this...
X x;
x.fsm(eEventA, -1, 2.0);
x.fsm(eEventB, "xyz");
x.fsm(eEventC, 42);
I'm having trouble figuring out how to get the template function to invoke the correct handler. If I simply switch on the eventId and pass through the variable arguments, it won't compile because handlers don't exist for all the parameter combinations (e.g., there's no eventA() handler that accepts eventB() arguments, which I would not want anyway).
My guess is that there is some elegant way to do this, but it is eluding me.
If you didn't have C++11 template parameter packs, the natural choice would be to declare a type for each event, inheriting from a base event type, and package the eventData in that. That's what I'd recommend. You can use dynamic type to verify that the right thing is getting dispatched, and if that slows things down disable the check in production mode.
Use a pointer-to-member-function to identify the event to the dispatcher. This eliminates the need for an enumeration, and encodes the type of the dispatch directly into the templated dispatcher.
This does, however, require that the dispatched functions be public.
template<typename... P, typename... A> void fsm(void (X::*event)( P ... ),
const A&... eventData) {
this->*event( eventData ... );
}
x.fsm( &X::eventB, 5, 1.3 );
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With