Skip to content

Commit

Permalink
Merge branch 'main' of github.com:parallel101/cppguidebook
Browse files Browse the repository at this point in the history
  • Loading branch information
archibate committed Aug 25, 2024
2 parents ff3ee98 + 79cca33 commit 4da96d3
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 5 deletions.
47 changes: 45 additions & 2 deletions docs/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ TODO: println 参数演示

## 函数的返回值

函数可以没有返回值,只需要返回类型写 `void` 即可,这样的函数调用的目的只是为了他的副作用(如修改全局变量,输出文本到控制台,修改引用参数等)。
函数可以没有返回值,只需要声明函数时返回类型声明为 `void` 即可,调用这样的函数只是为了他的副作用(如修改全局变量,输出文本到控制台,修改引用参数等)。

```cpp
void compute()
Expand All @@ -22,19 +22,62 @@ void compute()
```

> {{ icon.tip }} 对于没有返回值(返回类型为 `void`)的函数,可以省略 `return` 不写。
```cpp
void compute()
{
// 没问题
}
```

> {{ icon.warn }} 对于有返回值的函数,必须写 return 语句,如果漏写,会出现可怕的未定义行为 (undefined behaviour)。编译器不会报错,而是到运行时才出现崩溃等现象,建议 GCC 用户开启 `-Werror=return-type` 让编译器检测此类错误。更多未定义行为可以看我们的[未定义行为列表](undef.md)章节。
> {{ icon.warn }} 对于返回类型不为 `void` 的函数,必须写 `return` 语句,如果漏写,会出现可怕的未定义行为 (undefined behaviour)。编译器不一定会报错,而是到运行时才出现崩溃等现象。建议 GCC 用户开启 `-Werror=return-type` 让编译器在编译时就检测此类错误,MSVC 则是开启 `/we4716`。更多未定义行为可以看我们的[未定义行为列表](undef.md)章节。
> {{ icon.detail }} 但有两个例外:1. main 函数是特殊的可以不写 return 语句,默认会自动帮你 `return 0;`。2. 具有 co_return 或 co_await 的协程函数可以不写 return 语句。
### 接住返回值

### 返回类型 `auto`

C++11 `auto` 可以用作函数的返回类型,但它只是一个**占位**,让我们得以后置返回类型。

```cpp
auto f() -> int;
// 等价于:
int f();
```

C++14 引入了函数**返回类型推导**`auto` 才算真正意义上的用做了函数返回类型,它会根据函数中的 `return` 表达式推导出函数的返回类型。

```cpp
int x = 1;
auto f() {
return x;
}
// 等价于:
int f() {
return x;
}

// 如果函数中没有return语句,那么 `auto` 会被自动推导为 `void`
auto f() {
std::println("hello");
}
// 等价于:
void f() {
std::println("hello");
}

// 值得注意的是,返回类型用 `auto` 来推导的函数,如果有多条 `return` 语句,那么他们必须是相同的类型;否则报错
auto f(int x) {
if (x > 0) {
return 1; // int
} else {
return 3.14; // double
}
} // 错误:有歧义,无法确定 auto 应该推导为 int 还是 double
```
<!-- decltype(auto)... -->
## 函数的参数
### 形参 vs 实参
Expand Down
58 changes: 55 additions & 3 deletions examples/error_code.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ int checkStdError(int ret) {
// return {};
// }

template <class T>
using expected = tl::expected<T, std::error_code>;
// template <class T>
// using expected = tl::expected<T, std::error_code>;

struct RAIIFile {
int fd;
Expand All @@ -133,8 +133,60 @@ struct RAIIFile {
// }

int main() {
RAIIFile file{expectedStdError(open("/tmp/test.log", O_WRONLY)).value()};
RAIIFile file{expectedStdError(::open("/tmp/test.log", O_WRONLY)).value()};
std::string s = "asasasas";
file.write(s).value();
return 0;
}

namespace screenshot1 {

namespace std {
using namespace ::tl;
using namespace ::std;
}

std::expected<int, std::error_code> expectedStdError(int ret) {
if (ret == -1) {
return std::unexpected{std::error_code(errno, std::generic_category())};
}
return ret;
}

struct File {
int fd;

explicit File(const char *path, int flags) {
fd = expectedStdError(::open(path, flags)).value();
}

tl::expected<size_t, std::error_code> write(std::span<const char> buf) {
return expectedStdError(::write(fd, buf.data(), buf.size()));
}
};

std::expected<int, std::error_code> sqrt(int x) {
if (x < 0)
return std::unexpected{make_error_code(std::errc::argument_out_of_domain)};

for (int i = 0;; i++)
if (i * i >= x)
return i;
}

}

namespace screenshot2 {

int sqrt(int x) {
if (x < 0) {
errno = EDOM;
return -1;
}

for (int i = 0;; i++)
if (i * i >= x)
return i;
}

}

0 comments on commit 4da96d3

Please sign in to comment.