diff options
author | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2018-07-08 13:58:02 +0900 |
---|---|---|
committer | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2018-07-08 13:58:02 +0900 |
commit | 62c7a8f5fc8ad8bd1e123d2535bc5001c15fa75b (patch) | |
tree | 589848b42246d3af3b6ff6ccda29052a6b57ecd2 | |
parent | c4acd8ece12622164caf396c06bd0f22ab3589f7 (diff) | |
download | libquotient-62c7a8f5fc8ad8bd1e123d2535bc5001c15fa75b.tar.gz libquotient-62c7a8f5fc8ad8bd1e123d2535bc5001c15fa75b.zip |
visit<>(): support catch-all visitors on the tail
-rw-r--r-- | lib/events/event.h | 66 |
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 |