在“ 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
以外的成员的类类型。
答案 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
,因为它只是充当占位符。
您可以将其替换为double
或char
,然后看到相同的结果。
给定的类类型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;
}