"QList
So a
QList<QRect>
is going to be an array of QRect *
but QList<QWidget *>
will be an array of QWidget *
- not QWidget **
. But how can we determine whether a type is a pointer at compile time?Update: This describes the method used in Qt for compilers lacking support for partial template specialisation. If you have partial specialisation, it can be done in a very straightforward way (see blog comments).
Well it seems to be done by abusing our favourite language.
QList
uses the QTypeInfo class - the interesting bits being:
template <typename T> char QTypeInfoHelper(T*(*)());
void* QTypeInfoHelper(...);
template <typename T>
class QTypeInfo
{
public:
enum {
isPointer = (1 == sizeof(QTypeInfoHelper((T(*)())0))),
int *
Now, consider the case of
QTypeInfo<int *>
. the last line expands to:isPointer = (1 == sizeof(QTypeInfoHelper( (int * (*) ()) 0)))
.Now I've added some spaces so that it can actually be read. It's saying, pass NULL - casted to a pointer to a function that accepts nothing and returns an
int *
- to one of the QTypeInfo functions.But to which 1 of the 2 overloads? Well, the C++ rule for resolving overloaded function calls is to select the function with the most specific matching argument types, assuming no ambiguity. In this case, our function call matches this candidate:
template <typename T> char QTypeInfoHelper(T * (*) ());
because
T
is int
. Now you won't actually find QTypeInfoHelper
defined anywhere because all sizeof
is interested in is the size of the return value of the function - it doesn't actually execute it. Now, the return type is a char
, which is of size 1, therefore isPointer
is true.int
Now we look at a non-pointer type,
int
. The tricky line expands to:isPointer = (1 == sizeof(QTypeInfoHelper( (int (*) ()) 0)))
.That function pointer argument type accepts nothing and returns an
int
. It's not going to match the same overload because it's looking for a pointer (the T *
):template <typename T> char QTypeInfoHelper(T * (*) ());
And
int
is no pointer. Therefore, it can only match the catch-all overload:void* QTypeInfoHelper(...);
which returns a
void*
and guess what:isPointer = (1 == sizeof(void *))
.is false (unless on an 8-bit machine :)). Therefore,
int
is correctly detected as not a pointer.Conclusion
QTypeInfo manages to determine whether a type is a pointer without:
- actually invoking a function (by merely checking the size of the return type)
- ever constructing an element of type
T
(which might otherwise cause side effects)
5 comments:
Hi,
some nitpickery: For pointers and basic types separate templates exists. I.e.
int* uses def. at qglobal.h:1366
int uses def. at qglobal.h:1453
Bye,
Stefan
You should look at Boost.TypeTraits library: all is implemented, tested and ported to every compiler
http://www.boost.org/doc/html/boost_typetraits/reference.html#boost_typetraits.is_pointer
> For pointers and basic types separate
> templates exists. I.e.
> int* uses def. at qglobal.h:1366
Yes, I missed the simpler way if doing it #ifndef QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION:
template <typename T>
class QTypeInfo
{
enum {
isPointer = false,
[...]
template <ypename T>
class QTypeInfo<T*>
{
enum {
isPointer = true,
> int uses def. at qglobal.h:1453
s/int/QRect then :)
It should be noted that the "two functions" approach is more powerfull then partial template specialization. Same Boost.TypeTraits has traits called is_convertible, which can be used to test if type D is convertible to type B. It can be implemented like this:
char overload(B);
void* overload(...);
D d;
.... sizeof(overload(d));
that's something that can't be done using partial specialization.
Vampires is not at all like in the movies or books. Sure, I understand. You are young you have the whole world open to you. You can be anything that you choose if you apply yourself and try hard to work toward that goal. But being a Vampire is not what it seems like. It’s a life full of good, and amazing things. We are as human as you are.. It’s not what you are that counts, But how you choose to be. Do you want a life full of interesting things? Do you want to have power and influence over others? To be charming and desirable? To have wealth, health, and longevity? contact the Vampires Lord on his Email: Richvampirekindom@gmail.com
Post a Comment