move event handler verification to the Event class

This commit is contained in:
Pixel-Tony 2025-01-09 23:21:25 +01:00
parent 17d387cd1a
commit b9771fa3af
3 changed files with 43 additions and 49 deletions

View File

@ -339,15 +339,15 @@ public:
[[nodiscard]] const TEventSubtype* getIf() const;
////////////////////////////////////////////////////////////
/// \brief Apply a visitor to the event
/// \brief Apply visitors to the event
///
/// \param visitor The visitor to apply
/// \param visitors Visitors to apply
///
/// \return The result of applying the visitor to the event
/// \return The result of applying visitors to the event
///
////////////////////////////////////////////////////////////
template <typename T>
decltype(auto) visit(T&& visitor) const;
template <typename... Ts>
decltype(auto) visit(Ts&&... visitors) const;
private:
////////////////////////////////////////////////////////////
@ -396,12 +396,8 @@ private:
return (std::is_invocable_v<Handler, const Ts&> || ...);
}
public:
template <typename Handler>
static constexpr bool isValidHandler()
{
return isInvokableWithAnyOf<Handler>(static_cast<decltype(m_data)*>(nullptr));
}
static constexpr bool isValidHandler = isInvokableWithAnyOf<Handler>(static_cast<decltype(m_data)*>(nullptr));
};
} // namespace sf

View File

@ -38,6 +38,28 @@
namespace sf
{
namespace priv
{
template <typename... Ts>
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 <typename... Ts>
OverloadSet(Ts...) -> OverloadSet<Ts...>;
struct DelayOverloadResolution
{
template <typename T>
DelayOverloadResolution(const T&)
{
}
};
} // namespace priv
////////////////////////////////////////////////////////////
template <typename TEventSubtype>
Event::Event(const TEventSubtype& eventSubtype)
@ -79,10 +101,21 @@ const TEventSubtype* Event::getIf() const
////////////////////////////////////////////////////////////
template <typename T>
decltype(auto) Event::visit(T&& visitor) const
template <typename... Ts>
decltype(auto) Event::visit(Ts&&... visitors) const
{
return std::visit(std::forward<T>(visitor), m_data);
static_assert(sizeof...(Ts) > 0, "Must provide at least one handler");
static_assert((isValidHandler<Ts> && ...),
"All event handlers must accept a single parameter, either a const reference or a value");
// Disable misc-const-correctness for this line since clang-tidy
// complains about it even though the code would become uncompilable
// NOLINTNEXTLINE(misc-const-correctness)
return std::visit(priv::OverloadSet{std::forward<Ts>(visitors)...,
[](const priv::DelayOverloadResolution&) { /* ignore */ }},
m_data);
}
} // namespace sf

View File

@ -28,50 +28,15 @@
#include <SFML/Window/Event.hpp>
#include <SFML/Window/WindowBase.hpp> // NOLINT(misc-header-include-cycle)
#include <utility>
namespace sf
{
namespace priv
{
template <typename... Ts>
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 <typename... Ts>
OverloadSet(Ts...) -> OverloadSet<Ts...>;
struct DelayOverloadResolution
{
template <typename T>
DelayOverloadResolution(const T&)
{
}
};
} // namespace priv
////////////////////////////////////////////////////////////
template <typename... Ts>
void WindowBase::handleEvents(Ts&&... handlers) // NOLINT(cppcoreguidelines-missing-std-forward)
{
static_assert(sizeof...(Ts) > 0, "Must provide at least one handler");
static_assert((Event::isValidHandler<Ts>() && ...),
"All event handlers must accept a single parameter, either a const reference or a value");
// 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<Ts>(handlers)..., [](const priv::DelayOverloadResolution&) { /* ignore */ }};
while (const std::optional event = pollEvent())
event->visit(overloadSet);
event->visit(handlers...);
}
} // namespace sf