Allow using Bind() with non-public inheritance in C++11 code

Using Bind() with a method of the class deriving from wxEvtHandler
non-publicly used to result in a compile-time error, but at least with C++11
we can detect this case and allow the code to compile.

Closes #17623.
This commit is contained in:
VZ
2016-11-29 19:32:40 +01:00
committed by GitHub
parent 4212202a9a
commit 5551932c25
5 changed files with 44 additions and 2 deletions

View File

@@ -79,6 +79,8 @@ All:
- Handle strings with embedded NULs in wxDataStream (Nitch). - Handle strings with embedded NULs in wxDataStream (Nitch).
- Don't crash in wxTextFile::GetLastLine() if the file is empty (crohr). - Don't crash in wxTextFile::GetLastLine() if the file is empty (crohr).
- Add wxString::cbegin() and cend() method (Lauri Nurmi). - Add wxString::cbegin() and cend() method (Lauri Nurmi).
- Allow using Bind() with event handlers non-publicly deriving from
wxEvtHandler and/or wxTrackable in C++11 code (Raul Tambre, mmarsan).
All (GUI): All (GUI):

View File

@@ -332,7 +332,7 @@ class wxEventFunctorMethod
< <
Class, Class,
EventArg, EventArg,
wxConvertibleTo<Class, wxEvtHandler>::value != 0 wxIsPubliclyDerived<Class, wxEvtHandler>::value != 0
> >
{ {
private: private:

View File

@@ -34,5 +34,27 @@ struct wxConvertibleTo
}; };
}; };
// This is similar to wxConvertibleTo, except that when using a C++11 compiler,
// the case of D deriving from B non-publicly will be detected and the correct
// value (false) will be deduced instead of getting a compile-time error as
// with wxConvertibleTo. For pre-C++11 compilers there is no difference between
// this helper and wxConvertibleTo.
template <class D, class B>
struct wxIsPubliclyDerived
{
enum
{
#if __cplusplus >= 201103 || (defined(_MSC_VER) && _MSC_VER >= 1600)
// If C++11 is available we use this, as on most compilers it's a
// built-in and will be evaluated at compile-time.
value = std::is_base_of<B, D>::value && std::is_convertible<D*, B*>::value
#else
// When not using C++11, we fall back to wxConvertibleTo, which fails
// at compile-time if D doesn't publicly derive from B.
value = wxConvertibleTo<D, B>::value
#endif
};
};
#endif // _WX_META_CONVERTIBLE_H_ #endif // _WX_META_CONVERTIBLE_H_

View File

@@ -19,7 +19,7 @@
template <class T> template <class T>
struct wxIsStaticTrackable struct wxIsStaticTrackable
{ {
enum { value = wxConvertibleTo<T, wxTrackable>::value }; enum { value = wxIsPubliclyDerived<T, wxTrackable>::value };
}; };

View File

@@ -509,3 +509,21 @@ void EvtHandlerTestCase::UnbindFromHandler()
handler.ProcessEvent(e); handler.ProcessEvent(e);
} }
// This is a compilation-time-only test: just check that a class inheriting
// from wxEvtHandler non-publicly can use Bind() with its method, this used to
// result in compilation errors.
// Note that this test will work only on C++11 compilers, so we test this only
// for such compilers.
#if __cplusplus >= 201103
class HandlerNonPublic : protected wxEvtHandler
{
public:
HandlerNonPublic()
{
Bind(wxEVT_IDLE, &HandlerNonPublic::OnIdle, this);
}
void OnIdle(wxIdleEvent&) { }
};
#endif // C++11