%%
# 纲要
> 主干纲要、Hint/线索/路标
# Q&A
#### 已明确
#### 待明确
> 当下仍存有的疑惑
**❓<font color="#c0504d"> 有什么问题?</font>**
%%
# `inline` 说明符
`inline` 说明符有两个用途 [^1]:
1. **显式标记一个==静态存储持续性==的变量为"==内联变量=="**;
2. **显式标记一个函数为"==内联函数=="**;
除通过 `inline` 显式声明以外,也有**隐式的内联函数和内联变量**(参见后文)。
> [!caution]
>
> - `inline` 说明符不能被用于块作用域下的函数或变量声明
> - `inline` 说明符不能 **重声明 (re-declare)** 一个已在翻译单元中**被定义为 non-inline 的函数或变量**。
>
<br><br>
## 内联函数、内联变量的性质
> 参见[^1]
- 内联函数与变量的 "**==定义==**" **必须对 "每一个调用了该内联函数 or 使用了该内联变量的翻译单元" 可见**,编译器需要具此完成**内联替换**。
- 因此,**==内联函数、内联变量的定义==** 通常放置在头文件中,供所需使用的源文件引入。
- **试图在头文件中进行 `inline` 函数声明,而在源文件中进行函数定义是不可行的**。
- 内联函数与变量具有 "**==外部链接性==**",但**其定义可以存在于多个翻译单元**中,**只要所有定义均==保持一致==即可**,不会导致 "**重复定义**" 错误。
- 遵循**一体化定义规则**(One Definition Rule,**ODR**),要求所有翻译单元中出现的**定义必须完全一致**。
- 链接器会忽略重复的定义,只保留一个。
- 内联函数与变量尽管可存在多份定义,但 **==只会有一份实体==**,**被引入了其定义的==所有翻译单元所共享==**
(在每个翻译单元中具有相同的地址,即所有翻译单元共同引用同一实体)
- **内联函数作用域内**的 **==局部静态变量==** 也被 **所有翻译单元所共享**。
> [!NOTE] 一体化定义规则(One Definition Rule,ODR)
>
> C++ 规定:
>
> - **普通外部链接性函数:** 在整个程序中**只能有一个定义**。多个定义将导致**链接错误**。
> - **内联函数:** 可以在多个翻译单元中有**相同的定义**,但所有定义必须**完全相同**。链接器会**合并所有的相同定义**,保留一个有效的函数定义。
<br><br>
# 内联函数
`inline` 关键字标识的函数为 "**内联函数**",该关键字的作用是 **==指示==(而非强制)** 编译器使用 "**==函数的内联替换==**" 来替代 "**函数调用**"。
"**内联替换**" 是指**在编译时将 "==函数调用语句==" 直接替换为 "==函数体内执行代码=="**,从而 **==省略==/不产生函数调用过程**:
- 可**省去函数调用开销**(如栈帧的创建销毁、参数传递等);
- 但**会增大编译生成的程序体积**(函数体代码在每个函数调用处都被重复地内嵌)。
> [!info] 除 `inline` 显式标识的内联函数外,还有 "隐式内联函数"
> [!caution] `inline` 只是个**提示**,**编译器会根据其自身的优化选择来决定是否实际执行"内联替换"**:
>
> - 编译器**可以忽略 `inline` 声明**,不为内联函数执行内联替换,例如函数体较大或涉及复杂的控制结构(如循环和递归)等。
> - 编译器**可以为未标记 `inline` 的函数**在编译时使用内联替换进行优化;
>
> > *Since this meaning of the keyword inline is non-binding,*
> > - *compilers are free to use inline substitution for any function that's not marked inline,*
> > - *and are free to generate function calls to any function marked inline.*
>
<br>
### 内联函数的特性
![[#内联函数、内联变量的性质]]
<br>
### 隐式内联函数
"**隐式内联函数**" 是指未使用 `inline` 显式声明,但**默认具有 `inline` 特性**的函数。
以下函数均为 **==隐式内联函数==**:
- 类中的下列函数:
- **在类定义内部直接定义的任何函数**(包括成员函数和非成员函数,例如类定义中完整定义的友元函数)
- 除非被附加到一个具名模块(since C++20)
- **隐式生成的成员函数**(例如编译器生成的默认构造函数等)
- **在首次声明时声明为 `= default` 的任何成员函数**
- **在首次声明时==声明为`constexpr`== 或 `consteval` 的函数**
- **声明为 `= deleted` 的函数**(其 `deleted` 定义可以出现在多个翻译单元中)
<br><br>
# 内联变量(since C++17)
以下情况声明一个**内联变量**(inline variable):
- (1)**显式声明为 `inline`** 的 **静态存储持续性** 变量(静态成员变量、命名空间作用域变量)
- `inline` 全局变量、`inline const` 全局常量、`inline constexpr` 全局常量
- `inline` 函数中的 **`static` 静态局部变量**
- 类中的 `inline` 静态成员变量、 `constexpr` 静态成员变量
- (2)**在首次声明中==声明为 `constexpr`== 的静态成员变量**(隐式内联变量)
> [!NOTE] 内联变量具有 "**外部链接性**",包括 `inline` 全局变量、`inline const` 或 `inline constexpr` 全局常量等
<br>
### 内联变量的作用
内联变量消除了将 c++代码打包为 "**header-only 库**" 的主要障碍:
- C++17 之前,**全局变量**、**类的静态成员变量** 只能在全局作用域下进行一次性定义,由于具有 "**外部链接性**",因此通常只能在 `.cpp` 中定义。
- **如果放在头文件中,头文件被多个源文件包含后会触导致 "重复定义" 错误**。
- C++17 引入了 "**内联变量**" 后,**使用 ==`inline` 关键字==**,可以将全局变量或静态成员变量都**直接放在头文件中定义**。所有引入该头文件的翻译单元都将**持有一份自己的内联变量 =="定义"==**,**==而不会导致重定义问题==**,同时 **==所有翻译单元中的变量共享同一个实体==**。
> [!summary]
>
> - 头文件中定义的 **静态全局变量** 为**内部链接性**,每个引用该头文件的翻译单元中 **"独立"持有一份该变量的实体**,互不相同。
> - 头文件中定义的 "**内联变量**" 具有 **==外部链接性==**,在整个程序中只有一份实体,**被所有引入该头文件的翻译单元所共享**:
> [!caution] `inline` 静态数据成员必须在 "==类内部==" 进行定义&初始化,不能在类外定义&初始化。
>
> ```cpp
> // my.h
> class MyClass {
> public:
> // static int stcMemberVar = 5; // Error: 不允许对静态数据成员类内初始化
> static int stcMemberVar;
> static inline int inlineStcMemberVar = 15; // allowed(仅允许类内初始值方式)
> };
>
> int MyClass::stcMemberVar = 5; // 静态数据成员类外初始化. 该语句需要放在`.cpp`中, 若放在头文件中会导致 "重复定义".
> // inline int MyClass::inlineStcMemberVar = 15; // Error: 不允许类外定义.
> ```
>
<br>
### 内联变量的性质
![[#内联函数、内联变量的性质]]
### 使用示例
示例一:在头文件中定义 "**全局内联变量**"
```cpp title:inline_variable.h
#ifndef INLINE_VARIABLE_H
#define INLINE_VARIABLE_H
inline int globalInlineVar = 42; // 外部链接性, 但内联变量允许多个翻译单元包含, 不会导致重复定义错误, 且共享同一变量实体.
inline const int globalInlineConst = 55; // 外部链接性, 同上.
#endif
```
示例二:在头文件中定义 "**类的静态内联数据成员**"(**==必须且只能在类内定义和初始化==**)
```cpp
class Config {
public:
static inline const int MaxConnections = 100; // 常量
static inline double Pi = 3.14159; // 可变值
};
```
<br><br>
# Buffer
## 闪念
> sudden idea
## 候选资料
> Read it later
<br>
# ♾️参考资料
# Footnotes
[^1]: [inline specifier - cppreference.com](https://en.cppreference.com/w/cpp/language/inline)