简体   繁体   中英

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 XY::* , 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 )

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
}

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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM