I just found the following code in Qt and I'm a bit confused what's happening here.
Especially as to what reinterpret_cast<T>(0)
does?
template <class T>
inline T qobject_cast(const QObject *object)
{
// this will cause a compilation error if T is not const
register T ptr = static_cast<T>(object);
Q_UNUSED(ptr);
#if !defined(QT_NO_MEMBER_TEMPLATES) && !defined(QT_NO_QOBJECT_CHECK)
reinterpret_cast<T>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T>(const_cast<QObject *>(object)));
#endif
return static_cast<T>(const_cast<QObject *>(reinterpret_cast<T>(0)->staticMetaObject.cast(const_cast<QObject *>(object))));
}
Anyone care to explain?
This is a little complicated...
Remember that qobject_cast<T>(obj)
is a way to dynamically cast a QObject
to the target type T
which also derives from QObject
. Now, for this to work, the macro Q_OBJECT
should be included in the definition of class T
.
Apparently, the qt_check_for_QOBJECT_macro
call is for checking that the class really contains the Q_OBJECT macro. When the macro is expanded, it contains the following definitions:
template <typename T> inline void qt_check_for_QOBJECT_macro(const T &_q_argument) const
{ int i = qYouForgotTheQ_OBJECT_Macro(this, &_q_argument); i = i; }
template <typename T1, typename T2>
inline int qYouForgotTheQ_OBJECT_Macro(T, T) { return 0; }
So if you have an object x
of type T
and an object y
of type U
, the call x->qt_check_for_QOBJECT_macro(y)
calls the function qYouForgotTheQ_OBJECT_Macro
with parameters of types T*
and U*
. Because the function is templated with a single type parameter, the types T
and U
must be the same.
Now, if you call x->qt_check_for_QOBJECT_macro(x)
then you should expect the types to be the same and for the compilation to trivially succeed. However, remember that this
has the same type as the class the method was defined in. So if x
is of a class that was derived from T but doesn't contain its own definition of qt_check_for_QOBJECT_macro
, the call will fail.
So we have a way to check if the target type T contains the correct mechanism for the dynamic cast, but we don't have a object of type T to call this method on yet. That's what the reinterpret_cast<T>(0)
is for. We don't need an actual object as this
, since the compiler only needs the object types for the check to succeed. Instead, we call a method on a null pointer of type T.
I don't think this is allowed by the C++ standard, but it works since this
isn't actually used inside the method.