From 62c7a8f5fc8ad8bd1e123d2535bc5001c15fa75b Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Sun, 8 Jul 2018 13:58:02 +0900 Subject: visit<>(): support catch-all visitors on the tail --- lib/events/event.h | 66 +++++++++++++++++++++++++++++++++++------------------- 1 file 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(*eptr) ? static_cast(eptr.get()) : nullptr; } - template - inline auto visit(const BaseEventT& event, FnT visitor, - DefaultT&& defaultValue) + // A single generic catch-all visitor + template + inline auto visit(const BaseEventT& event, FnT&& visitor) + -> decltype(visitor(event)) + { + return visitor(event); + } + + template + constexpr auto is_event_v = std::is_base_of>::value; + + template + constexpr auto needs_cast_v = !std::is_convertible>::value; + + // A single type-specific void visitor + template + inline auto visit(const BaseEventT& event, FnT&& visitor) -> std::enable_if_t< - std::is_convertible>::value, - fn_return_t> + is_event_v && needs_cast_v && + std::is_void>::value> { using event_type = fn_arg_t; if (is(event)) - return visitor(static_cast(event)); - return std::forward>(defaultValue); + visitor(static_cast(event)); } - template - inline fn_return_t visit(const Event& event, FnT visitor) + // A single type-specific non-void visitor with an optional default value + template + inline auto visit(const BaseEventT& event, FnT&& visitor, + fn_return_t&& defaultValue = {}) + -> std::enable_if_t< + is_event_v && needs_cast_v, + fn_return_t> // non-voidness is guarded by defaultValue type { using event_type = fn_arg_t; if (is(event)) return visitor(static_cast(event)); - // Cannot define in terms of the previous overload because - // fn_return_t may be void and void() is not a valid default - // parameter value. - return fn_return_t(); + return std::forward>(defaultValue); } - template - inline auto visit(const Event& event, FnT visitor1, FnTs&&... visitors) + // A chain of 2 or more visitors + template + inline auto visit(const BaseEventT& event, FnT1&& visitor1, + FnT2&& visitor2, FnTs&&... visitors) + -> std::enable_if_t, fn_return_t> { - using event_type1 = fn_arg_t; + using event_type1 = fn_arg_t; if (is(event)) return visitor1(static_cast(event)); - - return visit(event, std::forward(visitors)...); + return visit(event, std::forward(visitor2), + std::forward(visitors)...); } - template - inline auto visit(const event_ptr_tt& eptr, FnTs&&... visitors) + // An adaptor accepting a pointer-like object instead of an event + template + inline auto visit(const EventHolderT& e, FnTs&&... visitors) + -> decltype(visit(*e, std::forward(visitors)...)) { - using return_type = decltype(visit(*eptr, visitors...)); - if (eptr) - return visit(*eptr, visitors...); + using return_type = decltype(visit(*e, std::forward(visitors)...)); + if (e) + return visit(*e, std::forward(visitors)...); return return_type(); } } // namespace QMatrixClient -- cgit v1.2.3