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::*,Ycan only be a class type. The following formulation ofIsClass<T>exploits the property (and picksintarbitrarily 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)
An object's class defines how the object is implemented. The class defines object's internal state and the implementation of its operations. In contrast, an object's type only refers to its interface - a set of requests to which it can respond.
IsSubclassOf. Which indicates that Derived is a subclass of Base , but that Base is (obviously) not a subclass of itself.
Use the typeof operator to check the type of a variable in TypeScript, e.g. if (typeof myVar === 'string') {} . The typeof operator returns a string that indicates the type of the value and can be used as a type guard in TypeScript.
In short, it's because the standard says so.
According to [dcl.mptr]/2 (I'm including only the relevant parts here):
[ Example:
struct X { int a; }; struct Y; double X::* pmd; char Y::* pmc;. . .
The declaration ofpmdis well-formed even thoughXhas no members of typedouble. Similarly, the declaration ofpmcis well-formed even thoughYis an incomplete type.
. . .
Basically, as long as a type S is known to be of class type, the construct S::* is well-formed.
So you could even have this:
int main()
{
struct S;
cout << IsClass<S>::value; // still prints 1
}
What I don't understand is why picking
intasXworks, 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)
It does not have to be int, as it just performs its role as a placeholder.
You can replace that with double or char and see the same result coming.
It doesn't matter at all whether the given class type T does have a member function, because what IsClass tries to see is just that expression:
X Y::*
is well-formed.
This is just like you don't need an actual function definition (non-member function) merely to declare a type of pointer to that function as follows:
int main()
{
// It doesn't matter whether there's a function int (*)(int, int, int) indeed because it's just merely a declaration
using FuncP = int (*)(int, int, int);
FuncP P;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With