QVariant: fix HasIsNullMethod for final classes
HasIsNullMethod uses the accepted C++98 idiom to
check for members that might be inherited from
baseclasses.
The technique, however, requires inheriting from
the type-under-test, which fails for C++11 final
classes.
Fortunately, under C++11 we have much better
support for static type introspection: sfinae
for expressions. We use this here (see decltype()
use in qvariant_p.h) to write a C++11 version of
HasIsNullMethod that works with final classes, too.
However, since this technique required decltype()
support in the compiler, Q_DECL_FINAL can no longer
be used for both method and class markup. So we
declare a new Q_DECL_FINAL_CLASS which is only
set iff the compiler supports decltype(), too.
MSVC 2005 and 2008 support a non-standard, but
sufficiently compatible, version of override/final,
but no decltype(). A later patch will use MSVC
'override/'sealed' to implement Q_DECL_{OVERRIDE,FINAL}
for these compilers, but I currently don't see a
version of HasIsNullMethod that could support these
two, so the split off of Q_DECL_FINAL_CLASS is in
anticipation of that commit. If someone _does_ find
an implementation of HasIsNullMethod that works on
MSVC2005 and 2008 sealed classes, then it's a simple
matter of s/Q_DECL_FINAL_CLASS/Q_DECL_FINAL/g.
This code has been tested on GCC 4.7 (prerelease)
and GCC 4.8 (prerelease).
Change-Id: I8700c8307d79a74d45fef0aec1c6027b4a922a43
Reviewed-by: Jędrzej Nowacki <jedrzej.nowacki@nokia.com>
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
bb10
parent
dbab994b2c
commit
73a5ce5195
|
|
@ -415,9 +415,15 @@ QT_END_INCLUDE_NAMESPACE
|
|||
#ifdef Q_COMPILER_EXPLICIT_OVERRIDES
|
||||
# define Q_DECL_OVERRIDE override
|
||||
# define Q_DECL_FINAL final
|
||||
# ifdef Q_COMPILER_DECLTYPE // required for class-level final to compile in qvariant_p.h
|
||||
# define Q_DECL_FINAL_CLASS final
|
||||
# else
|
||||
# define Q_DECL_FINAL_CLASS
|
||||
# endif
|
||||
#else
|
||||
# define Q_DECL_OVERRIDE
|
||||
# define Q_DECL_FINAL
|
||||
# define Q_DECL_FINAL_CLASS
|
||||
#endif
|
||||
|
||||
//defines the type for the WNDPROC on windows
|
||||
|
|
|
|||
|
|
@ -203,6 +203,19 @@ class QVariantIsNull
|
|||
/// \internal
|
||||
/// This class checks if a type T has method called isNull. Result is kept in the Value property
|
||||
/// TODO Can we somehow generalize it? A macro version?
|
||||
#if defined(Q_COMPILER_DECLTYPE) // C++11 version
|
||||
template<typename T>
|
||||
class HasIsNullMethod {
|
||||
struct Yes { char unused[1]; };
|
||||
struct No { char unused[2]; };
|
||||
Q_STATIC_ASSERT(sizeof(Yes) != sizeof(No));
|
||||
|
||||
template<class C> static decltype(static_cast<const C*>(0)->isNull(), Yes()) test(int);
|
||||
template<class C> static No test(...);
|
||||
public:
|
||||
static const bool Value = (sizeof(test<T>(0)) == sizeof(Yes));
|
||||
};
|
||||
#else // C++98 version (doesn't work for final classes)
|
||||
template<typename T, bool IsClass = QTypeInfo<T>::isComplex>
|
||||
class HasIsNullMethod
|
||||
{
|
||||
|
|
@ -211,7 +224,7 @@ class QVariantIsNull
|
|||
Q_STATIC_ASSERT(sizeof(Yes) != sizeof(No));
|
||||
|
||||
struct FallbackMixin { bool isNull() const; };
|
||||
struct Derived : public T, public FallbackMixin {};
|
||||
struct Derived : public T, public FallbackMixin {}; // <- doesn't work for final classes
|
||||
template<class C, C> struct TypeCheck {};
|
||||
|
||||
template<class C> static Yes test(...);
|
||||
|
|
@ -227,6 +240,7 @@ class QVariantIsNull
|
|||
public:
|
||||
static const bool Value = false;
|
||||
};
|
||||
#endif
|
||||
|
||||
// TODO This part should go to autotests during HasIsNullMethod generalization.
|
||||
Q_STATIC_ASSERT(!HasIsNullMethod<bool>::Value);
|
||||
|
|
@ -236,6 +250,12 @@ class QVariantIsNull
|
|||
Q_STATIC_ASSERT(!HasIsNullMethod<SelfTest2>::Value);
|
||||
struct SelfTest3 : public SelfTest1 {};
|
||||
Q_STATIC_ASSERT(HasIsNullMethod<SelfTest3>::Value);
|
||||
struct SelfTestFinal1 Q_DECL_FINAL_CLASS { bool isNull() const; };
|
||||
Q_STATIC_ASSERT(HasIsNullMethod<SelfTestFinal1>::Value);
|
||||
struct SelfTestFinal2 Q_DECL_FINAL_CLASS {};
|
||||
Q_STATIC_ASSERT(!HasIsNullMethod<SelfTestFinal2>::Value);
|
||||
struct SelfTestFinal3 Q_DECL_FINAL_CLASS : public SelfTest1 {};
|
||||
Q_STATIC_ASSERT(HasIsNullMethod<SelfTestFinal3>::Value);
|
||||
|
||||
template<typename T, bool HasIsNull = HasIsNullMethod<T>::Value>
|
||||
struct CallFilteredIsNull
|
||||
|
|
|
|||
Loading…
Reference in New Issue