C++--- 类型萃取 ---is_array && is_enum/is_union/is_class
背景
定义在<type_traits>中,用于判断一个类型是否是数组类型,是否是枚举类型,是否是联合类型,是否是非联合类型的类类型,属于基础的类型判断。
代码实现
gcc 官网:https://gcc.gnu.org/
gcc 代码下载:https://mirrors.tuna.tsinghua.edu.cn/help/gcc.git/
gcc 版本代码:gcc-7.5.0(branch 分支)
文件位置:gcc/libstdc++-v3/include/std/type_traits
注意:以下的代码实现省略了一些宏定义部分,实际的代码还是参考 gcc 源码,这里仅用作相关原理分析。
实现分析
is_array
is_array 的普通版本继承了 false_type,默认返回 false 类型,只有匹配到_Tp[_Size]或者_Tp[]是才特化为 true_type,返回 true 类型,说明 is_array 只会识别这两种数组的类型。
is_enum/is_union/is_class
这三种类型之所以放到一起,是因为他们都是 C++语言的关键字类型,所以它们的识别也是跟整个程序编译过程相关的。可以看到它们的实现继承了 integral_constant 模板,里面包含一个 bool 类型的值,这个值分别由函数__is_enum/__is_union/__is_class 求出。
下面我们就来初步看一下这个__is_enum 函数的调用过程(省略中间的调用过程),我们上面提到的三个内建函数就在 c-common.c 中定义。
实际上在代码语义分析阶段,会对语句进行分析,在这中间的过程中将会调用 cp_parser_primary_expression 函数进行语义分析,同时将相关的关键字进行标识,依次向下调用 cp_parser_trait_expr,在该函数中将 kind 标识为对应的值,最后调用 finish_trait_expr 函数,在该函数中调用 trait_expr_value 计算 bool 值,实际上是使用前面记录的标识判断是否是对应的类型。
鉴于中间的调用过程很复杂,这里我们只是暂时初步的调用流程。实际上可以这样理解,对于这样的关键字类型,在编译阶段就可以计算出来,所以调用了编译阶段提供的内建函数。
使用案例
通过上面的例子,我们也能看到如下的几点:
is_array
std::array 并不是数组类型(这里指原生数组),std::array 是 STL 实现的与原生数组类似的功能
type[]和 type[size]都能表示一个数组
is_enum:只能识别枚举类型和枚举类
is_union:识别联合类型
is_class
struct 也是类类型,特殊点在于它的成员变量都是 public 的
类指针,类引用都不是类类型
const 修饰的类也是类类型
枚举类不是类类型(class 关键字类似与作用域,使得枚举类型的使用更加安全)
联合类型不是类类型,但联合类型中定义的类是类类型
在语句中定义不完整的 struct 和 class 也是类类型。
总结
is_array
std::array 并不是数组类型(这里指原生数组),std::array 是 STL 实现的与原生数组类似的功能
type[]和 type[size]都能表示一个数组
is_enum:只能识别枚举类型和枚举类
is_union:识别联合类型
is_class
struct 也是类类型,特殊点在于它的成员变量都是 public 的
类指针,类引用都不是类类型
const 修饰的类也是类类型
枚举类不是类类型(class 关键字类似与作用域,使得枚举类型的使用更加安全)
联合类型不是类类型,但联合类型中定义的类是类类型
在语句中定义不完整的 struct 和 class 也是类类型。
版权声明: 本文为 InfoQ 作者【桑榆】的原创文章。
原文链接:【http://xie.infoq.cn/article/76e71d6657ee31fefe1097ed8】。文章转载请联系作者。
评论