diff --git a/include/wx/event.h b/include/wx/event.h index 39ca40725d..1c9b794fd9 100644 --- a/include/wx/event.h +++ b/include/wx/event.h @@ -144,9 +144,43 @@ inline wxEventFunction wxEventFunctionCast(void (wxEvtHandler::*func)(T&)) wxGCC_WARNING_RESTORE_CAST_FUNCTION_TYPE() } +// Special hack to remove "noexcept" from the function type when using C++17 or +// later: static_cast<> below would fail to cast a member function pointer to a +// member of a derived class to the base class if noexcept is specified for the +// former, so remove it first if necessary. +#if __cplusplus >= 201703L + +namespace wxPrivate +{ + +// Generic template version, doing nothing. +template +struct RemoveNoexceptEventHandler +{ + using type = T; +}; + +// Specialization removing noexcept when it's specified. +// +// Note that this doesn't pretend to be generally suitable, this is just enough +// to work in our particular case. +template +struct RemoveNoexceptEventHandler +{ + using type = R (C::*)(E&); +}; + +} // namespace wxPrivate + +#define wxREMOVE_NOEXCEPT_EVENT_HANDLER(pmf) \ + static_cast::type>(pmf) +#else +#define wxREMOVE_NOEXCEPT_EVENT_HANDLER(pmf) pmf +#endif + // Try to cast the given event handler to the correct handler type: #define wxEVENT_HANDLER_CAST( functype, func ) \ - wxEventFunctionCast(static_cast(&func)) + wxEventFunctionCast(static_cast(wxREMOVE_NOEXCEPT_EVENT_HANDLER(&func))) // The tag is a type associated to the event type (which is an integer itself, diff --git a/tests/events/evthandler.cpp b/tests/events/evthandler.cpp index 6be6c2d1ec..dce3f762a5 100644 --- a/tests/events/evthandler.cpp +++ b/tests/events/evthandler.cpp @@ -122,6 +122,9 @@ public: void OnEvent(wxEvent&) { g_called.method = true; } void OnAnotherEvent(AnotherEvent&); void OnIdle(wxIdleEvent&) { g_called.method = true; } +#ifdef wxHAS_NOEXCEPT + void OnIdleNoExcept(wxIdleEvent&) noexcept { } +#endif private: wxDECLARE_EVENT_TABLE(); @@ -138,6 +141,10 @@ wxBEGIN_EVENT_TABLE(MyClassWithEventTable, wxEvtHandler) EVT_MYEVENT(MyClassWithEventTable::OnMyEvent) EVT_MYEVENT(MyClassWithEventTable::OnEvent) +#ifdef wxHAS_NOEXCEPT + EVT_IDLE(MyClassWithEventTable::OnIdleNoExcept) +#endif + // this shouldn't compile: //EVT_MYEVENT(MyClassWithEventTable::OnIdle) //EVT_IDLE(MyClassWithEventTable::OnAnotherEvent)