Check that all WindowBase::handleEvents arguments handle some events

This commit is contained in:
kimci86 2025-01-25 23:39:20 +01:00 committed by Chris Thrasher
parent 23afdc2f9e
commit efb207c849
3 changed files with 35 additions and 1 deletions

View File

@ -34,6 +34,7 @@
#include <SFML/System/Vector2.hpp>
#include <type_traits>
#include <variant>
@ -395,11 +396,22 @@ private:
template <typename T, typename... Ts>
[[nodiscard]] static constexpr bool isInParameterPack(const std::variant<Ts...>*)
{
return (std::is_same_v<T, Ts> || ...);
return std::disjunction_v<std::is_same<T, Ts>...>;
}
template <typename T>
static constexpr bool isEventSubtype = isInParameterPack<T>(decltype (&m_data)(nullptr));
friend class WindowBase;
template <typename Handler, typename... Ts>
[[nodiscard]] static constexpr bool isInvocableWithEventSubtype(const std::variant<Ts...>*)
{
return std::disjunction_v<std::is_invocable<Handler&, Ts&>...>;
}
template <typename Handler>
static constexpr bool isEventHandler = isInvocableWithEventSubtype<Handler>(decltype (&m_data)(nullptr));
};
} // namespace sf

View File

@ -61,6 +61,7 @@ template <typename... Handlers>
void WindowBase::handleEvents(Handlers&&... handlers)
{
static_assert(sizeof...(Handlers) > 0, "Must provide at least one handler");
static_assert((Event::isEventHandler<Handlers> && ...), "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

View File

@ -10,6 +10,7 @@
#include <WindowUtil.hpp>
#include <chrono>
#include <memory>
#include <type_traits>
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<int>()](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{});
};
}