Allow using noexcept methods with event tables macros
Explicitly remove noexcept before static-casting the member function pointer to the base class pointer type to avoid compilation error with C++17. Add a test checking that this does work now. Closes #18721.
This commit is contained in:
		@@ -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 <typename T>
 | 
			
		||||
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 <typename R, typename C, typename E>
 | 
			
		||||
struct RemoveNoexceptEventHandler<R (C::*)(E&) noexcept>
 | 
			
		||||
{
 | 
			
		||||
    using type = R (C::*)(E&);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace wxPrivate
 | 
			
		||||
 | 
			
		||||
#define wxREMOVE_NOEXCEPT_EVENT_HANDLER(pmf) \
 | 
			
		||||
    static_cast<wxPrivate::RemoveNoexceptEventHandler<decltype(pmf)>::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<functype>(&func))
 | 
			
		||||
    wxEventFunctionCast(static_cast<functype>(wxREMOVE_NOEXCEPT_EVENT_HANDLER(&func)))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// The tag is a type associated to the event type (which is an integer itself,
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user