Skip to content

Commit 0e0837e

Browse files
committed
more complete intro auto
1 parent 4da96d3 commit 0e0837e

File tree

1 file changed

+85
-17
lines changed

1 file changed

+85
-17
lines changed

docs/functions.md

Lines changed: 85 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44

55
# 自定义函数
66

7+
```cpp
8+
int square(int x) {
9+
}
10+
```
11+
712
## 调用函数
813
914
```cpp
@@ -35,38 +40,65 @@ void compute()
3540
3641
### 接住返回值
3742

43+
## 函数的参数
44+
45+
### 形参 vs 实参
46+
47+
### 按引用传参 vs 按值传参
48+
49+
TODO:和 Python、Java 对比
50+
51+
### C 风格变长参数
52+
53+
## 模板函数
54+
55+
TODO:更多介绍函数
56+
57+
## `auto` 神教
58+
59+
### 变量 `auto`
60+
3861
### 返回类型 `auto`
3962

40-
C++11 `auto` 可以用作函数的返回类型,但它只是一个**占位**,让我们得以后置返回类型。
63+
C++11 引入的 `auto` 关键字可以用作函数的返回类型,但它只是一个“占位”,让我们得以后置返回类型,并没有多大作用,非常残废
4164

4265
```cpp
4366
auto f() -> int;
4467
// 等价于:
4568
int f();
4669
```
4770

48-
C++14 引入了函数**返回类型推导**`auto` 才算真正意义上的用做了函数返回类型,它会根据函数中的 `return` 表达式推导出函数的返回类型。
71+
> {{ icon.fun }} 闹了半天,还是要写返回类型,就只是挪到后面去好看一点……
72+
73+
> {{ icon.detail }} 当初引入后置返回类型实际的用途是 `auto f(int x) -> decltype(x * x) { return x * x; }` 这种情况,但很容易被接下来 C++14 引入的真正 `auto` 返回类型推导平替了。
74+
75+
C++14 引入了函数**返回类型推导**`auto` 才算真正意义上能用做函数返回类型,它会自动根据函数中的 `return` 表达式推导出函数的返回类型。
4976

5077
```cpp
51-
int x = 1;
52-
auto f() {
53-
return x;
78+
auto f(int x) {
79+
return x * x; // 表达式 `x * x` 的类型为 int,所以 auto 类型推导为 int
5480
}
5581
// 等价于:
5682
int f() {
57-
return x;
83+
return x * x;
5884
}
85+
```
86+
87+
如果函数中没有 `return` 语句,那么 `auto` 会被自动推导为 `void`,非常方便。
5988
60-
// 如果函数中没有return语句,那么 `auto` 会被自动推导为 `void`
89+
```cpp
6190
auto f() {
6291
std::println("hello");
6392
}
6493
// 等价于:
6594
void f() {
6695
std::println("hello");
6796
}
97+
```
98+
99+
值得注意的是,返回类型用 `auto` 来推导的函数,如果有多条 `return` 语句,那么他们必须都返回相同的类型,否则报错。
68100

69-
// 值得注意的是,返回类型用 `auto` 来推导的函数,如果有多条 `return` 语句,那么他们必须是相同的类型;否则报错
101+
```cpp
70102
auto f(int x) {
71103
if (x > 0) {
72104
return 1; // int
@@ -76,20 +108,56 @@ auto f(int x) {
76108
} // 错误:有歧义,无法确定 auto 应该推导为 int 还是 double
77109
```
78110
79-
<!-- decltype(auto)... -->
111+
`auto` 还有一个缺点是,无法用于“分离声明和定义”的情况。因为推导 `auto` 类型需要知道函数体,才能看到里面的 `return` 表达式是什么类型。所以当 `auto` 返回类型被用于函数的非定义声明时,会直接报错。
80112
81-
## 函数的参数
113+
```cpp
114+
auto f(); // 错误:看不到函数体,无法推导返回类型
82115
83-
### 形参 vs 实参
116+
auto f() { // 编译通过:auto 推导为 int
117+
return 1; // 1 是 int 类型的表达式
118+
}
119+
```
84120

85-
### 按引用传参 vs 按值传参
86-
87-
TODO:和 Python、Java 对比
121+
因此,`auto` 通常只适用于头文件中“就地定义”的 `inline` 函数,不适合需要“分离 .cpp 文件”的函数。
88122

89123
### 参数类型 `auto`
90124

91-
### C 风格变长参数
125+
C++20 引入了**模板参数推导**,可以让我们在函数参数中也使用 `auto`
92126

93-
## 模板函数
127+
TODO: 介绍
94128

95-
TODO:更多介绍函数
129+
传统的,基于类型重载的:
130+
131+
```cpp
132+
int square(int x) {
133+
return x * x;
134+
}
135+
136+
double square(double x) {
137+
return x * x;
138+
}
139+
140+
int main() {
141+
square(2); // 4(调用 int 版重载)
142+
square(3.14); // 9.8596(调用 double 版重载)
143+
// 如果现在又需要 float 版呢?又得写一版重载,内容还是完全一样的,浪费时间
144+
}
145+
```
146+
147+
基于 `auto` 模板参数推导的:
148+
149+
```cpp
150+
auto square(auto x) {
151+
return x * x;
152+
}
153+
154+
int main() {
155+
square(2); // 4(auto 推导为 int)
156+
square(3.14); // 9.8596(auto 推导为 double)
157+
// 即使未来产生了 float 版的需求,也不用添加任何代码,因为是 square 是很方便的模板函数
158+
}
159+
```
160+
161+
### `auto` 推导为引用
162+
163+
TODO: 继续介绍 `auto &`, `auto const &`, `auto &&`, `decltype(auto)`, `auto *`, `auto const *`

0 commit comments

Comments
 (0)