确定类型是否为类类型?

时间:2018-06-21 18:41:12

标签: c++ templates sfinae typetraits partial-specialization

在“ C ++模板-完整指南-第二版”一书的第19.8.4章中,作者展示了如何在编译时确定类型是否为类类型:

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

本段说明部分专业化如何检测类类型:

  

...仅类类型可以用作指针成员类型的基础。也就是说,在X Y::*形式的类型构造中,Y只能是类类型。以下IsClass<T>的表述利用了该属性(并为类型int任意选择了X

我不明白的是,即使我们使用完全没有成员的结构int测试X,为什么选择IsClass<>作为S仍然可行也适用于具有除int以外的成员的类类型。

2 个答案:

答案 0 :(得分:9)

简而言之,这是因为标准如此规定

根据[dcl.mptr]/2(在此仅包括相关部分):

  

[示例:

struct X {
  int a;
};
struct Y;

double X::* pmd;
char Y::* pmc;
     

。 。 。
  即使pmd没有类型为X的成员,double的声明也是格式正确的。同样,pmc的声明格式正确,即使Y是不完整的类型。
  。 。

基本上,只要已知类型S属于类类型,结构S::*的格式就正确。

所以您甚至可以拥有这个:

int main()
{
    struct S;
    cout << IsClass<S>::value; // still prints 1
}

答案 1 :(得分:4)

  

我不理解的是为什么将int选为X是有效的,即使我们测试的IsClass <>都没有成员的结构S(它也适用于具有非int成员的类类型。

它不必是int,因为它只是充当占位符。 您可以将其替换为doublechar,然后看到相同的结果。

给定的类类型T是否确实具有成员函数并不重要,因为IsClass试图看到的只是该表达式:

X Y::*

格式正确

这就像您不需要实际的函数定义(非成员函数)只是声明指向该函数的指针的类型,如下所示:

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