In Chapter 19.8.4 of the book "C++ Templates - The Complete Guide - Second Edition", the authors show how one can determine if a type is a class type in compile-time:
#include <iostream>
#include <type_traits>
using namespace std;
template <typename T, typename = void_t<>>
struct IsClass : false_type { };
template <typename T>
struct IsClass<T, void_t<int T::*>> : true_type { };
int main()
{
struct S { };
cout << IsClass<S>::value; // prints 1
}
This paragraph explains how the partial specialization detects a class type:
... only class types can be used as the basis of pointer-to-member types. That is, in a type construct of the form
X Y::*
,Y
can only be a class type. The following formulation ofIsClass<T>
exploits the property (and picksint
arbitrarily for typeX
)
What I don't understand is why picking int
as X
works, even if we test IsClass<>
with a struct S
that has no members at all (It also works for class types having a member other than int
)