理解C++ Type Traits

在 C++ 中, Type Traits(类型特性)是一组极其强大的模板类和函数, 它们为我们提供了一种在编译时查询, 修改和操作类型信息的机制. Type Traits 是 C++ 标准库 <type_traits> 头文件的核心内容, 其背后利用了模板元编程(Template Meta Programming)这一高深的技术, 使得程序能够在编译时进行诸如类型检查, 类型转换和类型选择等操作, 进而显著提高代码的安全性, 性能和灵活性.

1. 查询或判断类

基础类型判断

这类 Traits 主要用于判断一个类型是否属于某种特定的类别, 并且会返回一个布尔值. 下面是一些常用的基础类型判断:

复合类型判断

复合类型判断可以帮助我们判断一个类型是否为基础类型, 对象类型, 复合类型或引用类型等.

类型属性

类型属性判断可以帮助我们了解一个类型是否具有某些特定的属性, 比如是否为常量类型, 易变类型或平凡类型等.

查询支持的操作

我们还可以查询一个类型是否支持某些操作, 比如是否可以用指定的参数类型构造, 是否有默认构造函数, 是否支持移动赋值操作等.

查询类型关系

2. 类型修改类

这类 Traits 用于在编译时修改类型, 例如添加或移除引用, 指针, 常量限定符等.

CV 相关

引用

指针

符号

3. 其他类型变换

Type Traits 如何工作

看了上述这些 type traits 之后, 我们不禁想知道它是如何实现的. 翻开对应的代码, 我们可以看到其本质还是模板元编程, 在编译期完成.

模板特化

这里我们以is_integral为例, 来观察它的实现:

可以看到首先对输入参数做了取消constvolatile的操作, 接着传给__is_integral_helper.

/// is_integral
template<typename _Tp>
  struct is_integral
  : public __is_integral_helper<__remove_cv_t<_Tp>>::type
  { };

再看__is_integral_helper的实现, 编译器完整的实现比较长, 这里只截取其中一部分作为说明.

template<typename>
struct __is_integral_helper
  : public false_type { };

template<>
struct __is_integral_helper<bool>
  : public true_type { };

template<>
struct __is_integral_helper<char>
  : public true_type { };

template<>
struct __is_integral_helper<int>
  : public true_type { };

template<>
struct __is_integral_helper<long>
  : public true_type { };

// ... more case

其实可以看到这里用到了模板编程:

所以我们看到is_integral本质是通过模板特化实现的.

条件组合

对于复合类型的查询, 则是通过组合基础类型的判断实现. 以is_fundamentalis_compound为例, 前者组合了三种简单类型查询: is_arithmetic,is_void, is_null_pointer; 而后者则是对前者的取反操作.

template<typename _Tp>
struct is_fundamental
  : public __or_<is_arithmetic<_Tp>, is_void<_Tp>, is_null_pointer<_Tp>>::type
  { };

/// is_compound
template<typename _Tp>
struct is_compound : public __bool_constant<!is_fundamental<_Tp>::value> { };

总结

C++ Type Traits 是一种强大的编译时编程工具, 它允许程序员在编译时处理类型信息, 从而提高代码的安全性和性能. 通过合理使用 Type Traits, 可以编写出更加通用, 灵活和高效的模板代码.

参考链接