diff --git a/include/SFML/Window/Event.hpp b/include/SFML/Window/Event.hpp index df2972b6a..4ff5a5a3a 100644 --- a/include/SFML/Window/Event.hpp +++ b/include/SFML/Window/Event.hpp @@ -34,6 +34,7 @@ #include +#include #include @@ -339,26 +340,26 @@ public: [[nodiscard]] const TEventSubtype* getIf() const; //////////////////////////////////////////////////////////// - /// \brief Apply a visitor to the event + /// \brief Apply handlers to the event /// - /// \param visitor The visitor to apply + /// \param handlers Handlers to apply /// - /// \return The result of applying the visitor to the event + /// \return The result of applying the handlers to the event /// //////////////////////////////////////////////////////////// - template - decltype(auto) visit(T&& visitor); + template + decltype(auto) visit(Handlers&&... handlers); //////////////////////////////////////////////////////////// - /// \brief Apply a visitor to the event + /// \brief Apply handlers to the event /// - /// \param visitor The visitor to apply + /// \param handlers Handlers to apply /// - /// \return The result of applying the visitor to the event + /// \return The result of applying the handlers to the event /// //////////////////////////////////////////////////////////// - template - decltype(auto) visit(T&& visitor) const; + template + decltype(auto) visit(Handlers&&... handlers) const; private: //////////////////////////////////////////////////////////// @@ -395,11 +396,20 @@ private: template [[nodiscard]] static constexpr bool isInParameterPack(const std::variant*) { - return (std::is_same_v || ...); + return std::disjunction_v...>; } template - static constexpr bool isEventSubtype = isInParameterPack(decltype (&m_data)(nullptr)); + static constexpr bool isEventSubtype = isInParameterPack(static_cast(nullptr)); + + template + static constexpr bool isInvokableWithAnyOf(std::variant*) + { + return std::disjunction_v...>; + } + + template + static constexpr bool isValidHandler = isInvokableWithAnyOf(static_cast(nullptr)); }; } // namespace sf diff --git a/include/SFML/Window/Event.inl b/include/SFML/Window/Event.inl index daabd2fd3..1e48e6bcb 100644 --- a/include/SFML/Window/Event.inl +++ b/include/SFML/Window/Event.inl @@ -38,6 +38,20 @@ namespace sf { +namespace priv +{ +template +struct OverloadSet : Ts... +{ + using Ts::operator()...; +#if defined(_MSC_VER) && !defined(__clang__) + unsigned char dummy; // Dummy variable to ensure that this struct is not empty thus avoiding a crash due to an MSVC bug +#endif +}; +template +OverloadSet(Ts...) -> OverloadSet; +} // namespace priv + //////////////////////////////////////////////////////////// template Event::Event(const TEventSubtype& eventSubtype) @@ -79,18 +93,20 @@ const TEventSubtype* Event::getIf() const //////////////////////////////////////////////////////////// -template -decltype(auto) Event::visit(T&& visitor) +template +decltype(auto) Event::visit(Handlers&&... handlers) { - return std::visit(std::forward(visitor), m_data); + static_assert((isValidHandler && ...), "All handlers must accept a single event subtype parameter"); + return std::visit(priv::OverloadSet{std::forward(handlers)...}, m_data); } //////////////////////////////////////////////////////////// -template -decltype(auto) Event::visit(T&& visitor) const +template +decltype(auto) Event::visit(Handlers&&... handlers) const { - return std::visit(std::forward(visitor), m_data); + static_assert((isValidHandler && ...), "All handlers must accept a single event subtype parameter"); + return std::visit(priv::OverloadSet{std::forward(handlers)...}, m_data); } } // namespace sf diff --git a/include/SFML/Window/WindowBase.inl b/include/SFML/Window/WindowBase.inl index 2c5c89c7b..4f482432b 100644 --- a/include/SFML/Window/WindowBase.inl +++ b/include/SFML/Window/WindowBase.inl @@ -35,17 +35,6 @@ namespace sf { namespace priv { -template -struct OverloadSet : Ts... -{ - using Ts::operator()...; -#if defined(_MSC_VER) && !defined(__clang__) - unsigned char dummy; // Dummy variable to ensure that this struct is not empty thus avoiding a crash due to an MSVC bug -#endif -}; -template -OverloadSet(Ts...) -> OverloadSet; - struct DelayOverloadResolution { template @@ -55,21 +44,14 @@ struct DelayOverloadResolution }; } // namespace priv - //////////////////////////////////////////////////////////// -template -void WindowBase::handleEvents(Ts&&... handlers) // NOLINT(cppcoreguidelines-missing-std-forward) +template +void WindowBase::handleEvents(Handlers&&... handlers) { - static_assert(sizeof...(Ts) > 0, "Must provide at least one handler"); - - // Disable misc-const-correctness for this line since clang-tidy - // complains about it even though the code would become uncompilable - - // NOLINTNEXTLINE(misc-const-correctness) - priv::OverloadSet overloadSet{std::forward(handlers)..., [](const priv::DelayOverloadResolution&) { /* ignore */ }}; + static_assert(sizeof...(Handlers) > 0, "Must provide at least one handler"); while (std::optional event = pollEvent()) - event->visit(overloadSet); + event->visit(std::forward(handlers)..., [](priv::DelayOverloadResolution) { /* ignore */ }); } } // namespace sf