%%
# 纲要
> 主干纲要、Hint/线索/路标
# Q&A
#### 已明确
#### 待明确
> 当下仍存有的疑惑
**❓<font color="#c0504d"> 有什么问题?</font>**
%%
# 类型命名
C++中,可通过以下声明语句将一个"**名称**" 声明为**指代某一个类型**:
- class declaration
- union declaration
- enum declaration
- **类型别名声明**
- typedef declaration:`typedef type-id identifier`
- type alias declaration: `using identifier = type-id`
<br>
# 类型别名
C++中的 "类型别名" 提供了一种为**现有类型**定义**新名称**的方法。
C++中提供了两种方式来定义类型别名:
- **`typedef` 声明**(typedef declaration):`typedef type-id identifier;`
- **`using` 声明**(type alias declaration): `using identifier = type-id;`
**类型别名的作用域**遵循 C++中的**通用作用域规则**,其**作用域取决于==类型别名声明的位置**==。
类型别名可以在**全局作用域**、**命名空间作用域**、**类作用域**、**函数作用域**内声明。
示例:
```cpp title:type_alias_exam.cpp
typedef char Byte // 定义Byte为char类型的别名
using Integer = int; // 定义Integer为int类型的别名
using IntVector = std::vector<int> // 定义IntVector为`std::vector<int>`类型的别名
//using的优势在于能够很容易地定义模板别名
template<typename T>
using MapOfString = std::map<std::string, T>;
```
> [!NOTE] 类型别名不具有 "链接性",其只是编译器解析类型时使用的一个别名,只在声明所在的翻译单元的编译期间有效。
> [!caution] 宏定义不属于类型别名!
>
> 预处理器指令 `#define` 定义的"**宏**" 只是让**预处理器 "单纯"地进行==名称"替换"**==,因此可能出现如下情况:
>
> ```cpp
> #define FLOAT_POINTER float*
> FLOAT_POINTER pa, pb; // 预处理器将该声明转换为 `float* pa, pb`; 使得 pb 是 float 变量而非指针
> ```
>
> 而 `typedef` 设置类型别名则不会有上述问题:
>
> ```cpp
> typedef char* byte_ptr;
> byte_ptr a, b; // 等价于 char *a, *b;
> ```
>
>
> [!caution] 类型别名前的 cv 限定符是对整个 "给定类型" 的修饰
>
> 当使用一个类型别名时,如果前面存在 `const` 限定符,则 `const` 是对这整个 "**==给定类型==**" 的修饰。
> 如果该别名是一个 **"指针" 类型的别名**,则意味着声明了一个 "**常量指针**" 类型。
>
> 如下所示:
>
> ```cpp
> using pstring = char*;
> // or typedef char* pstring;
>
> // const 是对"给定类型"的修饰
> // `pstring` 是一个指向 char 的"指针类型".
> // 因此下一语句中的 `const` 是对"指针类型"的修饰, 表示"常量指针", 而不是对 `char` 的修饰.
> const pstring cstr = nullptr; // cstr 是指向 char 的常量指针 (const pointer)
> const pstring *ps; // ps 是一个指针, 该指针指向一个"指向 `char` 类型的常量指针".
> ```
<br>
## `typedef` 声明
`typedef` 是 C 和早期 C++中定义类型别名的传统方式。
```cpp title:typedef_exam.cpp
// ------------------1.为"类型"声明别名
typedef std::vector<std::pair<std::string, int>> vec_str_i; // 'vec_str_i'是类型别名
// ------------------2.为 "函数类型" 声明别名
// 为一个函数类型声明别名
typedef bool Func1(const string&, const string&); // `Func1`是函数类型的类型别名
// 为lengthCompare函数的函数类型声明别名; 等价于上述语句
typedef decltype(lengthCompare) Func2;
// ------------------3.为函数指针声明别名
// 为一个函数指针声明别名
typedef void (*FuncPtr)(const string&, const string&); // `FuncPtr`是函数指针的类型别名
// 为一个指向lengthCompare函数的函数类型的"函数指针"声明别名
typedef decltype(lengthCompare) *FuncPtr2; // `FuncPtr`是函数指针的类型别名
```
注意 `typedef` 声明静态数组别名时,数组大小放在最后:
```cpp
typedef int int_array[4]; // `int_array` 是 `int[4]`类型的别名
int_array a; // a是一个含有4个int元素的数组类型
// 等价声明:
using int_array = int[4];
```
<br>
## `using` 声明
C++11 引入了 `using` 声明作为定义类型别名的现代替代方法。
![[_attachment/02-开发笔记/01-cpp/类型相关/cpp-类型别名.assets/IMG-cpp-类型别名-D3FF31C3EDADC6ECE67C135360BD5741.png|453]]
```cpp ++ title:using_typealias_exam.cpp
// --------------------1.使用using为"类型"声明别名
using vec_str_i = std::vector<std::pair<std::string, int>>; // 'vec_str_i'是类型别名
// --------------------2.使用using为一个"函数类型"声明别名
using F = int(int*, int);
F func1(int);
// --------------------3.使用using为一个"函数指针类型"声明别名
using PF = int(*)(int*, int);
PF funcptr = &f; // 函数指针
using FuncType = decltype(foo);
Functype* funcptr2 = &foo; // 函数指针
// --------------------4.使用using为一个"成员函数指针类型"声明别名
using FuncPtr = int (MyClass::*)(int*, int);
using ConstFuncPtr = int (MyClass::*)(int*, int) const;
FuncPtr = &MyClass::func;
ConstFuncPtr = &Myclass::constFunc;
```
<br><br>
## `using` 和 `typedef` 的差异
`typedef` 只能用于为 "**已存在类型(type)**" 声明别名。
由于"模版"不是一个类型,因此 **`typedef` 无法为 "类模版" 定义一个别名**。
`using` 声明支持为 "**模版**" 声明 **==模版别名==**。
<br><br>
# Buffer
## 闪念
> sudden idea
## 候选资料
> Read it later
# ♾️参考资料
# Footnotes