aboutsummaryrefslogtreecommitdiff
path: root/lib/events/event.h
diff options
context:
space:
mode:
authorKitsune Ral <Kitsune-Ral@users.sf.net>2018-07-08 13:58:02 +0900
committerKitsune Ral <Kitsune-Ral@users.sf.net>2018-07-08 13:58:02 +0900
commit62c7a8f5fc8ad8bd1e123d2535bc5001c15fa75b (patch)
tree589848b42246d3af3b6ff6ccda29052a6b57ecd2 /lib/events/event.h
parentc4acd8ece12622164caf396c06bd0f22ab3589f7 (diff)
downloadlibquotient-62c7a8f5fc8ad8bd1e123d2535bc5001c15fa75b.tar.gz
libquotient-62c7a8f5fc8ad8bd1e123d2535bc5001c15fa75b.zip
visit<>(): support catch-all visitors on the tail
Diffstat (limited to 'lib/events/event.h')
-rw-r--r--lib/events/event.h66
1 files changed, 43 insertions, 23 deletions
diff --git a/lib/events/event.h b/lib/events/event.h
index 2ba95b63..12903274 100644
--- a/lib/events/event.h
+++ b/lib/events/event.h
@@ -299,47 +299,67 @@ namespace QMatrixClient
return is<EventT>(*eptr) ? static_cast<EventT*>(eptr.get()) : nullptr;
}
- template <typename BaseEventT, typename FnT, typename DefaultT>
- inline auto visit(const BaseEventT& event, FnT visitor,
- DefaultT&& defaultValue)
+ // A single generic catch-all visitor
+ template <typename BaseEventT, typename FnT>
+ inline auto visit(const BaseEventT& event, FnT&& visitor)
+ -> decltype(visitor(event))
+ {
+ return visitor(event);
+ }
+
+ template <typename T>
+ constexpr auto is_event_v = std::is_base_of<Event, std::decay_t<T>>::value;
+
+ template <typename T, typename FnT>
+ constexpr auto needs_cast_v = !std::is_convertible<T, fn_arg_t<FnT>>::value;
+
+ // A single type-specific void visitor
+ template <typename BaseEventT, typename FnT>
+ inline auto visit(const BaseEventT& event, FnT&& visitor)
-> std::enable_if_t<
- std::is_convertible<DefaultT, fn_return_t<FnT>>::value,
- fn_return_t<FnT>>
+ is_event_v<BaseEventT> && needs_cast_v<BaseEventT, FnT> &&
+ std::is_void<fn_return_t<FnT>>::value>
{
using event_type = fn_arg_t<FnT>;
if (is<event_type>(event))
- return visitor(static_cast<event_type>(event));
- return std::forward<fn_return_t<FnT>>(defaultValue);
+ visitor(static_cast<event_type>(event));
}
- template <typename FnT>
- inline fn_return_t<FnT> visit(const Event& event, FnT visitor)
+ // A single type-specific non-void visitor with an optional default value
+ template <typename BaseEventT, typename FnT>
+ inline auto visit(const BaseEventT& event, FnT&& visitor,
+ fn_return_t<FnT>&& defaultValue = {})
+ -> std::enable_if_t<
+ is_event_v<BaseEventT> && needs_cast_v<BaseEventT, FnT>,
+ fn_return_t<FnT>> // non-voidness is guarded by defaultValue type
{
using event_type = fn_arg_t<FnT>;
if (is<event_type>(event))
return visitor(static_cast<event_type>(event));
- // Cannot define in terms of the previous overload because
- // fn_return_t<FnT> may be void and void() is not a valid default
- // parameter value.
- return fn_return_t<FnT>();
+ return std::forward<fn_return_t<FnT>>(defaultValue);
}
- template <typename FnT, typename... FnTs>
- inline auto visit(const Event& event, FnT visitor1, FnTs&&... visitors)
+ // A chain of 2 or more visitors
+ template <typename BaseEventT, typename FnT1, typename FnT2, typename... FnTs>
+ inline auto visit(const BaseEventT& event, FnT1&& visitor1,
+ FnT2&& visitor2, FnTs&&... visitors)
+ -> std::enable_if_t<is_event_v<BaseEventT>, fn_return_t<FnT1>>
{
- using event_type1 = fn_arg_t<FnT>;
+ using event_type1 = fn_arg_t<FnT1>;
if (is<event_type1>(event))
return visitor1(static_cast<event_type1&>(event));
-
- return visit(event, std::forward<FnTs>(visitors)...);
+ return visit(event, std::forward<FnT2>(visitor2),
+ std::forward<FnTs>(visitors)...);
}
- template <typename BaseEventT, typename... FnTs>
- inline auto visit(const event_ptr_tt<BaseEventT>& eptr, FnTs&&... visitors)
+ // An adaptor accepting a pointer-like object instead of an event
+ template <typename EventHolderT, typename... FnTs>
+ inline auto visit(const EventHolderT& e, FnTs&&... visitors)
+ -> decltype(visit(*e, std::forward<FnTs>(visitors)...))
{
- using return_type = decltype(visit(*eptr, visitors...));
- if (eptr)
- return visit(*eptr, visitors...);
+ using return_type = decltype(visit(*e, std::forward<FnTs>(visitors)...));
+ if (e)
+ return visit(*e, std::forward<FnTs>(visitors)...);
return return_type();
}
} // namespace QMatrixClient