Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determining whether a type is a class type?

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 of IsClass<T> exploits the property (and picks int arbitrarily for type X)

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)

like image 374
Benji Mizrahi Avatar asked Jun 21 '18 18:06

Benji Mizrahi


People also ask

What is the difference between a class and a type?

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.

How do you check if a class is a subclass in C#?

IsSubclassOf. Which indicates that Derived is a subclass of Base , but that Base is (obviously) not a subclass of itself.

How do I know my TS type?

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.


2 Answers

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 of pmd is well-formed even though X has no members of type double. Similarly, the declaration of pmc is well-formed even though Y is 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
}
like image 63
rustyx Avatar answered Oct 17 '22 06:10

rustyx


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)

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;
}
like image 4
Dean Seo Avatar answered Oct 17 '22 07:10

Dean Seo