template <typename T, typename U> class IsSubclass {
typedef char YesType;
struct NoType {
char padding[8];
};
static YesType subclassCheck(U*);
static NoType subclassCheck(...);
static T* t;
public:
static const bool value = sizeof(subclassCheck(t)) == sizeof(YesType);
};
Why the size of the padding array should be 8 instead of other sizes?
I wish to know the reason for using 8
CodePudding user response:
This seems to be outdated code. Since C 11, there is std::is_base_of
. Also, this approach of writing a type trait using two overloads with different sizeof
for their return types is rather old-fashioned. I could fill a whole answer to explain the history and evolution of how to write such a type trait. However, I think that is beyond the scope of this question.
It works like this: The T* t;
member is passed to the subclassCheck()
member method. Either t
can be implicitly converted to U*
. This is the case when U
is a public base class of T
. Then YesType subclassCheck(U*);
is called.
If U
is not a public base class of T
, then t
cannot be converted to U*
and NoType subclassCheck(...);
is called.
value
is the result of comparing the size of the return type of the called member function with the size of YesType
. If they match, you know that YesType subclassCheck(U*);
was called and that T
inherits from U
. Because sizeof
is an un-evaluated context, no function is actually called (that's why it is OK to have only declarations, no definitions of the member functions).
This only works when sizeof(NoType)
is different from sizeof(YesType)
. What NoType
actually contains is irrelevant as long as it makes sizeof(NoType)
different from sizeof(char)
.
There are many details that could be updated with newer C standards. typedef
-> using
. std::is_same
rather than using sizeof
to compare the types. And much more, but the whole approach is outdated. And also, C 11 introduced std::is_base_of
.