理解C++ Type Traits
在 C++ 中, Type Traits(类型特性)是一组极其强大的模板类和函数, 它们为我们提供了一种在编译时查询, 修改和操作类型信息的机制. Type Traits 是 C++ 标准库 <type_traits>
头文件的核心内容, 其背后利用了模板元编程(Template Meta Programming)这一高深的技术, 使得程序能够在编译时进行诸如类型检查, 类型转换和类型选择等操作, 进而显著提高代码的安全性, 性能和灵活性.
1. 查询或判断类
- 编译时类型检查: 可以在编译时确定某个类型是否满足特定的条件, 例如是否为整数类型, 是否为指针类型等.
- 类型转换: 在编译时对类型进行转换, 例如移除引用, 添加常量限定符等.
- 类型选择: 根据不同的条件在编译时选择不同的类型.
基础类型判断
这类 Traits 主要用于判断一个类型是否属于某种特定的类别, 并且会返回一个布尔值. 下面是一些常用的基础类型判断:
is_integral
: 判断一个类型是否为整型.is_floating_point
: 判断一个类型是否为浮点类型.is_pointer
: 判断一个类型是否为指针类型.
复合类型判断
复合类型判断可以帮助我们判断一个类型是否为基础类型, 对象类型, 复合类型或引用类型等.
is_fundamental
: 判断一个类型是否为基础类型(如整型, 浮点型, 布尔型等).is_object
: 判断一个类型是否为对象类型(不是函数, 引用或void
类型).is_compound
: 判断一个类型是否为复合类型(不是基础类型).is_reference
: 判断一个类型是否为引用类型.
类型属性
类型属性判断可以帮助我们了解一个类型是否具有某些特定的属性, 比如是否为常量类型, 易变类型或平凡类型等.
is_const
: 判断一个类型是否为常量类型.is_volatile
: 判断一个类型是否为易变类型.is_trivial
: 判断一个类型是否为平凡类型(默认构造函数, 析构函数和拷贝构造函数都是平凡的).
查询支持的操作
我们还可以查询一个类型是否支持某些操作, 比如是否可以用指定的参数类型构造, 是否有默认构造函数, 是否支持移动赋值操作等.
is_constructable
: 判断一个类型是否可以用指定的参数类型构造.is_default_constructible
: 判断一个类型是否有默认构造函数.is_nothrow_constructable
: 判断一个类型的构造函数是否不会抛出异常.is_move_assignable
: 判断一个类型是否支持移动赋值操作.is_destructible
: 判断一个类型是否有析构函数.
查询类型关系
is_same
: 判断两个类型是否相同.is_base_of
: 判断一个类型是否是另一个类型的基类.is_convertible
: 判断一个类型是否可以隐式转换为另一个类型.is_invocable
: 判断一个可调用对象是否可以用指定的参数类型调用.
2. 类型修改类
这类 Traits 用于在编译时修改类型, 例如添加或移除引用, 指针, 常量限定符等.
CV 相关
remove_cv
: 移除类型的const
和volatile
限定符.remove_const
: 移除类型的const
限定符.add_cv
: 为类型添加const
和volatile
限定符.add_const
: 为类型添加const
限定符.add_volatile
: 为类型添加volatile
限定符.
引用
remove_reference
: 移除类型的引用.add_lvalue_reference
: 为类型添加左值引用.add_rvalue_reference
: 为类型添加右值引用.
指针
remove_pointer
: 移除类型的指针.add_pointer
: 为类型添加指针.
符号
make_signed
: 将无符号类型转换为有符号类型.make_unsigned
: 将有符号类型转换为无符号类型.
3. 其他类型变换
decay
: 应用数组到指针, 函数到指针等转换, 移除引用和 cv 限定符等.enable_if
: 用于在编译时根据条件启用或禁用模板.conditional
: 根据条件在编译时选择不同的类型.common_type
: 找出多个类型的公共类型.result_of
: 用于推断可调用对象的返回类型(C++17 后被invoke_result
替代).
Type Traits 如何工作
看了上述这些 type traits 之后, 我们不禁想知道它是如何实现的. 翻开对应的代码, 我们可以看到其本质还是模板元编程, 在编译期完成.
模板特化
这里我们以is_integral
为例, 来观察它的实现:
可以看到首先对输入参数做了取消const
和volatile
的操作, 接着传给__is_integral_helper
.
再看__is_integral_helper
的实现, 编译器完整的实现比较长, 这里只截取其中一部分作为说明.
其实可以看到这里用到了模板编程:
__is_integral_helper
默认是false_type
.__is_integral_helper
对bool
,char
,int
,long
等类型做了特化, 设置其值为true_type
, 这样如果输入参数匹配到这些类型就会得到true
.
所以我们看到is_integral
本质是通过模板特化实现的.
条件组合
对于复合类型的查询, 则是通过组合基础类型的判断实现. 以is_fundamental
和is_compound
为例, 前者组合了三种简单类型查询: is_arithmetic
,is_void
, is_null_pointer
; 而后者则是对前者的取反操作.
总结
C++ Type Traits 是一种强大的编译时编程工具, 它允许程序员在编译时处理类型信息, 从而提高代码的安全性和性能. 通过合理使用 Type Traits, 可以编写出更加通用, 灵活和高效的模板代码.
参考链接
Tags: