Info
- Did you know that run-time dispatching over type-list can be implemented many different ways?
Example
template <template <class...> class TList, class TEvent, class... TEvents, class T, class TExpr>
constexpr auto dispatch(TList<TEvent, TEvents...>, const int id, const T& data,
const TExpr& expr) -> decltype(expr(TEvent{data})) {
switch (id) {
case TEvent::id:
return expr(TEvent{data});
default:
if constexpr (sizeof...(TEvents) > 0) {
return dispatch(TList<TEvents...>{}, id, data, expr);
}
}
return {};
}
Puzzle
-
Can you implement
dispatch
with the follwing methods?- if else
- jump table
- fold expressions
- ...
template <template<class...> class TList, class TEvent, class... TEvents, class T, class TExpr>
constexpr auto dispatch(TList<TEvent, TEvents...>, const int id, const T& data, const TExpr& expr) {
// TODO if else
return 0;
}
template <class... TEvents, class T, class TExpr>
constexpr auto dispatch(const int id, const T& data, const TExpr& expr) {
// TODO jump table
return 0;
}
template <class... TEvents, class T, class TExpr>
constexpr auto dispatch(const int id, const T& data, const TExpr& expr) {
// TODO fold expressions
return 0;
}
Solutions
template <template <class...> class TList, class TEvent, class... TEvents,
class T, class TExpr>
constexpr auto dispatch(TList<TEvent, TEvents...>, const int id, const T& data,
const TExpr& expr) -> decltype(expr(TEvent{data})) {
// if else
if (id == TEvent::id) {
return expr(TEvent{data});
} else if constexpr (sizeof...(TEvents) > 0) {
return dispatch(TList<TEvents...>{}, id, data, expr);
}
return 0;
}
template <class... TEvents, class T, class TExpr>
constexpr auto dispatch(const int id, const T& data, const TExpr& expr) {
// jump table
const auto jump_table = [expr](TEvents... events) {
return std::array{(expr(events))...};
}(TEvents{data}...);
return jump_table[id];
}
template <class... TEvents, class T, class TExpr>
constexpr auto dispatch(const int id, const T& data, const TExpr& expr) {
// fold expressions
return ([&](auto&& event) {
if (id == event.id) {
return expr(event);
}
return 0;
}(TEvents{data}) +
...);
}