Appearance
类型萃取 type_traits:原理与常用成员
一、什么是 type_traits
编译期「关于类型的属性/变换」的模板工具,形如常量/类型值:
- 查询(谓词)返回
std::integral_constant<bool,v>(v 是 bool 常量),有::value;C++17 可_v。 - 变换(transform)返回一个新类型,有
::type;C++14 提供_t后缀。
cpp
#include <type_traits>
static_assert(std::is_integral_v<int>); // true
static_assert(std::is_same_v<int, int>);
using T = std::remove_const_t<const int>; // int二、最核心:基于偏特化实现的 is_same / remove_const
cpp
template <typename T, typename U> struct is_same : std::false_type {};
template <typename T> struct is_same<T,T> : std::true_type {};
// 用途:T,T 完全相同时命中偏特化 → true
template <typename T> struct remove_const { using type = T; };
template <typename T> struct remove_const<const T> { using type = T; }; // 剥掉外层 conststd::integral_constant<bool, value> 与 true_type/false_type 提供 value 常量 + 类型标记,方便继承复用与标签派发。
三、常用工具分类记忆
| 类 | 成员 | 用途 |
|---|---|---|
| 属性查询 | is_integral/is_floating_point/is_enum/is_class/is_pointer/is_reference/is_const/is_volatile | 编译期判断类型 |
| 关系 | is_same、is_base_of、is_convertible、is_constructible | 类型关系检查 |
| 特性 | is_trivially_copyable、is_nothrow_move_constructible、is_empty | 容器/算法优化依据 |
| 变性 | remove_reference、remove_const/volatile、add_const、decay | 归一类型 |
| 选择 | conditional<b,T,F>::type、enable_if<cond,T>、common_type | 编译期 if / 返回类型 |
| 变换 | make_unsigned、underlying_type(枚举底层)、result_of/invoke_result | 类型运算 |
std::decay 语义(高频):去掉数组→指针、函数→函数指针、剥掉 cv/引用 → 即「值传参的样子」。常用于把任意传入 T 归一成能存进容器的值类型。
四、常见用途(HPC/库代码)
- 按特质选实现:容器根据
is_trivially_copyabledecide 能否 memcpy 或必须逐一拷贝构造。 - 完美转发后取类型:
std::remove_reference_t<decltype(x)>。 - 标签派发(tag dispatch):根据
is_arithmetic选不同重载。 if constexpr+ 谓词在函数里做编译期条件分支(替代一堆 enable_if)。std::invoke_result_t推导函数返回类型,用于模板包装返回值。
五、手写一个小 tuple 的结构(体现 type_traits 用处)
(了解即可)tuple 常实现为「递归继承」:Tuple<Head, Tail...> : private Head, Tuple<Tail...> 用继承顺序存储 + EBCO 空基类优化。面试少让人手写完整 tuple,更常见问 sizeof(tuple<>) 为什么往往不额外占——EBCO。
六、易错
is_same_v<T, const T>:T=int时为 false(一层 const 区分),remove_const后比较才 true。remove_reference只剥引用不剥 const;要剥干净用decay。- cv 在类型外层 vs 指针所指:
remove_const_p<const int*>剥不掉所指常性——只管「顶层」。这正是混淆点,答出区别即扎实。