diff options
author | Alexey Rusakov <Kitsune-Ral@users.sf.net> | 2022-08-01 18:09:47 +0200 |
---|---|---|
committer | Alexey Rusakov <Kitsune-Ral@users.sf.net> | 2022-09-04 18:42:11 +0200 |
commit | bde38f86337d6f49b34b38016ab088d2f48ec371 (patch) | |
tree | 66971b5864de14bbe17e2b7fa8cbf12adb325bf5 /lib | |
parent | 575534e7cca310c6d6195ab16d482bf9dfba755e (diff) | |
download | libquotient-bde38f86337d6f49b34b38016ab088d2f48ec371.tar.gz libquotient-bde38f86337d6f49b34b38016ab088d2f48ec371.zip |
concept EventClass
Constrain types to derive from Event (or the chosen class), where
applicable.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/connection.cpp | 2 | ||||
-rw-r--r-- | lib/connection.h | 2 | ||||
-rw-r--r-- | lib/eventitem.h | 4 | ||||
-rw-r--r-- | lib/events/event.h | 43 |
4 files changed, 30 insertions, 21 deletions
diff --git a/lib/connection.cpp b/lib/connection.cpp index a33ace51..d9268028 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -188,7 +188,7 @@ public: emit q->accountDataChanged(eventType); } - template <typename EventT, typename ContentT> + template <EventClass EventT, typename ContentT> void packAndSendAccountData(ContentT&& content) { packAndSendAccountData( diff --git a/lib/connection.h b/lib/connection.h index 66ed8b68..5afcfc2f 100644 --- a/lib/connection.h +++ b/lib/connection.h @@ -189,7 +189,7 @@ public: //! of that type. //! \note Direct chats map cannot be retrieved using this method _yet_; //! use directChats() instead. - template <typename EventT> + template <EventClass EventT> const EventT* accountData() const { return eventCast<EventT>(accountData(EventT::TypeId)); diff --git a/lib/eventitem.h b/lib/eventitem.h index 2e55a724..445f8265 100644 --- a/lib/eventitem.h +++ b/lib/eventitem.h @@ -46,7 +46,7 @@ public: const RoomEvent* event() const { return rawPtr(evt); } const RoomEvent* get() const { return event(); } - template <typename EventT> + template <EventClass<RoomEvent> EventT> const EventT* viewAs() const { return eventCast<const EventT>(evt); @@ -67,7 +67,7 @@ public: std::any& userData() { return data; } protected: - template <typename EventT> + template <EventClass<RoomEvent> EventT> EventT* getAs() { return eventCast<EventT>(evt); diff --git a/lib/events/event.h b/lib/events/event.h index 9d7c61a9..d0b63085 100644 --- a/lib/events/event.h +++ b/lib/events/event.h @@ -64,7 +64,11 @@ struct QUOTIENT_API EventTypeRegistry { class Event; -template <class EventT> +// TODO: move over to std::derived_from<Event> once it's available everywhere +template <typename EventT, typename BaseEventT = Event> +concept EventClass = std::is_base_of_v<BaseEventT, EventT>; + +template <EventClass EventT> bool is(const Event& e); //! \brief The base class for event metatypes @@ -206,13 +210,13 @@ private: //! //! This should not be used to load events from JSON - use loadEvent() for that. //! \sa loadEvent -template <typename EventT, typename... ArgTs> +template <EventClass EventT, typename... ArgTs> inline event_ptr_tt<EventT> makeEvent(ArgTs&&... args) { return std::make_unique<EventT>(std::forward<ArgTs>(args)...); } -template <class EventT> +template <EventClass EventT> constexpr const auto& mostSpecificMetaType() { if constexpr (requires { EventT::MetaType; }) @@ -226,7 +230,7 @@ constexpr const auto& mostSpecificMetaType() //! Use this factory template to detect the type from the JSON object //! contents (the detected event type should derive from the template //! parameter type) and create an event object of that type. -template <typename EventT> +template <EventClass EventT> inline event_ptr_tt<EventT> loadEvent(const QJsonObject& fullJson) { return mostSpecificMetaType<EventT>().loadFrom( @@ -238,7 +242,7 @@ inline event_ptr_tt<EventT> loadEvent(const QJsonObject& fullJson) //! Use this template to resolve the C++ type from the Matrix type string in //! \p matrixType and create an event of that type by passing all parameters //! to BaseEventT::basicJson(). -template <typename EventT> +template <EventClass EventT> inline event_ptr_tt<EventT> loadEvent(const QString& matrixType, const auto&... otherBasicJsonParams) { @@ -246,7 +250,7 @@ inline event_ptr_tt<EventT> loadEvent(const QString& matrixType, EventT::basicJson(matrixType, otherBasicJsonParams...), matrixType); } -template <typename EventT> +template <EventClass EventT> struct JsonConverter<event_ptr_tt<EventT>> : JsonObjectUnpacker<event_ptr_tt<EventT>> { // No dump() to avoid any ambiguity on whether a given export to JSON uses @@ -295,7 +299,7 @@ public: //! the returned value will be different. QString matrixType() const; - template <class EventT> + template <EventClass EventT> bool is() const { return Quotient::is<EventT>(*this); @@ -377,7 +381,7 @@ private: }; using EventPtr = event_ptr_tt<Event>; -template <typename EventT> +template <EventClass EventT> using EventsArray = std::vector<event_ptr_tt<EventT>>; using Events = EventsArray<Event>; @@ -400,8 +404,10 @@ using Events = EventsArray<Event>; //! your class will likely be clearer and more concise. //! \sa https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern //! \sa DEFINE_SIMPLE_EVENT -template <class EventT, class BaseEventT, typename ContentT = void> +template <typename EventT, EventClass BaseEventT, typename ContentT = void> class EventTemplate : public BaseEventT { + // Above: can't constrain EventT to be EventClass because it's incomplete + // by CRTP definition. public: static_assert( !std::is_same_v<ContentT, void>, @@ -522,7 +528,7 @@ public: // === is<>(), eventCast<>() and switchOnType<>() === -template <class EventT> +template <EventClass EventT> inline bool is(const Event& e) { if constexpr (requires { EventT::MetaType; }) { @@ -544,7 +550,7 @@ inline bool is(const Event& e) //! can be either "dumb" (BaseEventT*) or "smart" (`event_ptr_tt<>`). This //! overload doesn't affect the event ownership - if the original pointer owns //! the event it must outlive the downcast pointer to keep it from dangling. -template <class EventT, typename BasePtrT> +template <EventClass EventT, typename BasePtrT> inline auto eventCast(const BasePtrT& eptr) -> decltype(static_cast<EventT*>(&*eptr)) { @@ -567,7 +573,7 @@ inline auto eventCast(const BasePtrT& eptr) //! after calling this overload; if it is a temporary, this normally //! leads to the event getting deleted along with the end of //! the temporary's lifetime. -template <class EventT, typename BaseEventT> +template <EventClass EventT, typename BaseEventT> inline auto eventCast(event_ptr_tt<BaseEventT>&& eptr) { return eptr && is<std::decay_t<EventT>>(*eptr) @@ -576,12 +582,15 @@ inline auto eventCast(event_ptr_tt<BaseEventT>&& eptr) } namespace _impl { - template <typename FnT, class BaseT> - concept Invocable_With_Downcast = + template <typename FnT, typename BaseT> + concept Invocable_With_Downcast = requires + { + requires EventClass<BaseT>; std::is_base_of_v<BaseT, std::remove_cvref_t<fn_arg_t<FnT>>>; + }; } -template <class BaseT, typename TailT> +template <EventClass BaseT, typename TailT> inline auto switchOnType(const BaseT& event, TailT&& tail) { if constexpr (std::is_invocable_v<TailT, BaseT>) { @@ -596,7 +605,7 @@ inline auto switchOnType(const BaseT& event, TailT&& tail) } } -template <class BaseT, typename FnT1, typename... FnTs> +template <EventClass BaseT, typename FnT1, typename... FnTs> inline auto switchOnType(const BaseT& event, FnT1&& fn1, FnTs&&... fns) { using event_type1 = fn_arg_t<FnT1>; @@ -605,7 +614,7 @@ inline auto switchOnType(const BaseT& event, FnT1&& fn1, FnTs&&... fns) return switchOnType(event, std::forward<FnTs>(fns)...); } -template <class BaseT, typename... FnTs> +template <EventClass BaseT, typename... FnTs> [[deprecated("The new name for visit() is switchOnType()")]] // inline auto visit(const BaseT& event, FnTs&&... fns) { |