%%
# 纲要
> 主干纲要、Hint/线索/路标
# Q&A
#### 已明确
#### 待明确
> 当下仍存有的疑惑
**❓<font color="#c0504d"> 有什么问题?</font>**
# Buffer
## 闪念
> sudden idea
## 候选资料
> Read it later
%%
# 模版元编程
模板元编程(_template metaprogramming_,TMP)
# Type Traits 头文件
C++ 标准库头文件 `<type_traits>` 中提供了一系列用于进行 "**==类型处理==**"(**类型转换**、**类型查询**) 的**类模版**,
这些类提供了 "**在编译时==对类型进行查询和转换==**" 的功能,通常用于 "**模版元编程**" 设计中[^2]。

<br><br>
# type_traits 中模版的实现说明
### 类型转换模版的实现
示例一:`std::remove_reference<>` 等类模版的实现:通过 "**==struct"类型成员==** & "**==模版特例化==**" 进行实现[^3].
```cpp
// std::remove_reference<>的实现方式:通过"struct"类型成员 & "模版特例化" 进行实现.
namespace MySpace {
template <typename T>
struct remove_reference {
typedef T type;
};
template <typename T>
struct remove_reference<T&> { // 针对左值引用的 "模版特例化" 版本
typedef T type;
};
template <typename T>
struct remove_reference<T&&> { // 针对右值引用的 "模版特例化" 版本
typedef T type;
};
} // end namespace MySpace
int main() {
MySpace::remove_reference<int&>::type var = 25; // var是int类型.
return 0;
}
```
示例二:`std::remove_reference_t<>` 等带 `_t` 后缀的实现:通过定义 "**==别名模版==**" 得到
![[_attachment/02-开发笔记/01-cpp/模版与泛型编程/cpp-type_traits 头文件.assets/IMG-cpp-type_traits 头文件-0C7EC4D51FF1C2D0DE3C75C157465FC0.png|566]]
## 类型判断模版的实现
略。
- 原始版本,例如 `std::is_pointer<T>` 暂时不太能理解,似乎涉及到**编译器层面的判断**。
- `_v` 后缀版本,是定义的 "**变量模版**",例如 `std::is_pointer_v<T>` 是关于 `std::is_pointer<T>::value` 的变量模版。
# "类型转换" 模版
主要的**类型转换** 相关模版:
![[_attachment/02-开发笔记/01-cpp/模版与泛型编程/cpp-type_traits 头文件.assets/IMG-cpp-type_traits 头文件-3879CB28E522824038E1F5C0D24CF57E.png|658]]
这些模版类都 **接受一个模版参数 `T`**,而**给出==转换所得的另一类型==**。
当**无法进行类型转换**时,给出的将是 `T` 本身。
在具体用法上,有两种方式:
> [!NOTE] 关于 `<type_traits>` 中 "类型转换" 相关接口的使用说明
>
> `<type_traist>` 所提供的所有 "**==类型转换==**" 相关的类模版,有两种版本 [^1],
>
> - (1)**无 `_t` 后缀**的版本,其**具有一个公有成员 `type`**,由该成员给出对应类型;
> - 其实现是通过 **`struct` 模版内嵌套 `typedef`** 完成的,故必须通过其成员 `::type` 使用,且**需要由关键字 `typename` 明确指出为类型名**。
>
> >
>
> - (2)**带 `_t` 后缀**的版本(since C++14),其**本身直接给出对应类型**。
> - 其实现直接通过 "**==别名模版==**" 完成,故可直接使用,不再需要 `::type`。
>
>
> ![[_attachment/02-开发笔记/01-cpp/模版与泛型编程/cpp-type_traits 头文件.assets/IMG-cpp-type_traits 头文件-FD71E765C9C603309CA63B219289CE89.png|626]]
>
> ^1ecwlu
>
<br>
### CV 限定相关
`std::remove_const<>`,`std::remove_volatile<>`,`std::remove_cv<>` :
这些模板用于**移除类型的 `const`、`volatile` 修饰符**,或同时移除两者(`cv` 表示 `const-volatile`)。
```cpp
using T = const int;
using U = std::remove_const<T>::type; // U 是 int
```
`std::add_const`,`std::add_volatile`,`std::add_cv`:
这些模板用于**给类型添加 `const`、`volatile` 修饰符**,或同时添加两者。
```cpp
using T = int;
using U = std::add_const<T>::type; // U 是 const int
```
<br>
### 引用相关
`std::remove_reference<>`,`std::add_l_value_referece<>`,`std::add_rvalue_reference<>`:
这些模板用于移除类型的引用修饰符,或添加左值引用或右值引用。
```cpp
using T = int&;
using U = std::remove_reference<T>::type; // U 是 int
using V = std::add_rvalue_reference<U>::type; // V 是 int&&
```
### 指针相关
- `std::add_pointer<>`:用于将类型 `T` 转换对应指针类型 `T*`
- `std::remove_pointer<>`:用于将指针类型 `T*` 转为所指类型 `T`
```cpp
using U = std::add_pointer<int>::type; // U是int*
using V = std::remove_pointer<int*>::type; // U是int
```
### 获取衰变类型
`std::decay` 用于将类型“衰变”为它们**在函数传递中会被转换为的类型**,包括**移除引用、移除 `cv` 限定符、将数组转换为指针、将函数转换为函数指针**。
### 获取底层类型
对于**枚举类型**,`std::underlying_type` 用于获取其底层整型类型
```cpp
enum class MyEnum : unsigned int {};
using T = std::underlying_type<MyEnum>::type; // T 是 unsigned int
```
<br><br><br>
# "类型判断" 模版
> [!NOTE] 关于 `<type_traits>` 中各个接口的使用说明
>
> `<type_traist>` 所提供的所有 "**==类型判断==**" 相关的类模版,有两种版本 [^1],
>
> - (1)**无 `_v` 后缀**的版本,其**具有一个公有成员 `value`(`bool` 类型)**,**由该成员变量给出判断结果**。
> - (2)**带 `_v` 后缀**的版本(since C++14),其**本身是一个 "==变量模版=="**,**故可直接使用**。
> - 如图所示,在 `<type_traits>` 中的定义如下: ![[_attachment/02-开发笔记/01-cpp/模版与泛型编程/cpp-type_traits 头文件.assets/IMG-cpp-type_traits 头文件-BCFEBB80D51C82B32ECDA456C420BF05.png|503]]
>
说明示例:
```cpp
// 判断是否为整型
std::is_integral<T>::value // bool值
std::is_integral_v<T> // 与上等价, 为bool类型的变量模版. since C++14
// 判断是否为指针
std::is_pointer<T>::value // bool值
std::is_pointer_v<T> // 与上等价, 为bool类型的变量模版. since C++14
```
<br><br><br>
# 用途示例
### 灵活重载
示例一:为整数类型 (short, int, long long 等) 和非整型 (float, double) 实现不同的函数
```cpp
#include <type_traits>
using namespace std;
// 根据<type_traits>中提供的std::is_integral<T>()来判断类型, 为整数型和浮点型调用不同的函数
// 使用type_traits的好处在于:
// 对所有整型(包括short, int, long long)和非整型(float, double)只需要实现两个函数即可.
template <typename T>
void fool_impl(T val, true_type); // provide integral version
template <typename T>
void fool_impl(T val, false_type); // provide floating-point version.
template <typename T>
void foo(T val) {
fool_impl(val, std::is_integral<T>());
}
```
示例二:为任意类型,两个版本。
```cpp
#include <type_traits>
using namespace std;
template <typename T>
void foo_impl(const T &val, std::true_type);
template <typename T>
void foo_impl(const T& val, std::false_type);
template <typename T>
void foo(const T &val) { // 根据模版实例化时T的类型, 来调用对应的
// `std::is_pointer<T>()` 根据T的类型返回type `std::true_type` 或 `std::false_type`
foo_impl(val, std::is_pointer<T>());
}
// 上述实现等价于如下实现:
template <typename T>
void foo (const T& val); // 针对寻常type
template <typename T>
void foo<T*> (const T& val); // 针对pointer type
```
<br><br>
## 处理共通类型
共通类型(Common Type):可用于处理两种不同类型的值的类型.
例如,求两个不同类型的值的和或者最小值,就需要以共通类型作为返回值。
示例一:返回两个不同类型中的最小值
```cpp
#include <type_traits>
// 使用std::common_type<>来得到T1和T2的共通类型, 作为返回类型
template <typename T1, typename T2>
typename std::common_type<T1,T2>::type min(const T1 &x, const T2 &y);
// 如果T1和T2都是int或者long, 或者一个int另一个long, 则std::common_type<T1,T2>返回int.
// 如果其一是string, 而另一个是const char*, 则返回结果是string.
```
<br><br>
# ♾️参考资料
# Footnotes
[^1]: 《Effective Modern C++》Item9
[^2]: 《C++ Primer》P606
[^3]: 《C++ Primer》P628