From efb207c849d37f3d9f3395ff20eec35d59e09567 Mon Sep 17 00:00:00 2001 From: kimci86 Date: Sat, 25 Jan 2025 23:39:20 +0100 Subject: [PATCH] Check that all WindowBase::handleEvents arguments handle some events --- include/SFML/Window/Event.hpp | 14 +++++++++++++- include/SFML/Window/WindowBase.inl | 1 + test/Window/WindowBase.test.cpp | 21 +++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/include/SFML/Window/Event.hpp b/include/SFML/Window/Event.hpp index 9c84a09d1..bd1ca67fa 100644 --- a/include/SFML/Window/Event.hpp +++ b/include/SFML/Window/Event.hpp @@ -34,6 +34,7 @@ #include +#include #include @@ -395,11 +396,22 @@ 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)); + + friend class WindowBase; + + template + [[nodiscard]] static constexpr bool isInvocableWithEventSubtype(const std::variant*) + { + return std::disjunction_v...>; + } + + template + static constexpr bool isEventHandler = isInvocableWithEventSubtype(decltype (&m_data)(nullptr)); }; } // namespace sf diff --git a/include/SFML/Window/WindowBase.inl b/include/SFML/Window/WindowBase.inl index 730b9435a..14c82796e 100644 --- a/include/SFML/Window/WindowBase.inl +++ b/include/SFML/Window/WindowBase.inl @@ -61,6 +61,7 @@ template void WindowBase::handleEvents(Handlers&&... handlers) { static_assert(sizeof...(Handlers) > 0, "Must provide at least one handler"); + static_assert((Event::isEventHandler && ...), "Handlers must accept at least one subtype of sf::Event"); // Disable misc-const-correctness for this line since clang-tidy // complains about it even though the code would become incorrect diff --git a/test/Window/WindowBase.test.cpp b/test/Window/WindowBase.test.cpp index 66b01befc..58d404e80 100644 --- a/test/Window/WindowBase.test.cpp +++ b/test/Window/WindowBase.test.cpp @@ -10,6 +10,7 @@ #include #include +#include #include TEST_CASE("[Window] sf::WindowBase", runDisplayTests()) @@ -219,5 +220,25 @@ TEST_CASE("[Window] sf::WindowBase", runDisplayTests()) // Should compile if user provides both a specific handler and a catch-all windowBase.handleEvents([](const sf::Event::Closed&) {}, [](const auto&) {}); + + // Should compile if user provides a handler taking an event subtype by value or reference, + // but not rvalue reference because it would never be called. + windowBase.handleEvents([](sf::Event::Closed) {}); + windowBase.handleEvents([](const sf::Event::Closed) {}); + windowBase.handleEvents([](sf::Event::Closed&) {}); + windowBase.handleEvents([](const sf::Event::Closed&) {}); + + // Should compile if user provides a move-only handler + windowBase.handleEvents([p = std::make_unique()](const sf::Event::Closed&) {}); + + // Should compile if user provides a handler with deleted rvalue ref-qualified call operator + struct LvalueOnlyHandler + { + void operator()(const sf::Event::Closed&) & + { + } + void operator()(const sf::Event::Closed&) && = delete; + }; + windowBase.handleEvents(LvalueOnlyHandler{}); }; }