@chengzhao-dev/dsh-cpp-workflow 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -20
- package/README.en.md +18 -16
- package/README.md +18 -16
- package/cordis.patch.yml +2 -5
- package/lib/index.js +7 -8
- package/lib/workspace.js +14 -14
- package/locale/en.json +1 -1
- package/locale/zh.json +1 -1
- package/package.json +5 -5
- package/skills/building-cpp/SKILL.md +6 -6
- package/skills/building-cpp/assets/config/.clang-format +3 -38
- package/skills/building-cpp/assets/config/.clang-tidy +8 -39
- package/skills/building-cpp/assets/config/.clangd +2 -5
- package/skills/building-cpp/assets/config/.vscode/extensions.json +2 -1
- package/skills/building-cpp/assets/config/.vscode/settings.json +16 -1
- package/skills/building-cpp/assets/templates/projects/common/running-build.sh +29 -18
- package/skills/building-cpp/assets/templates/projects/multi/CMakeLists.txt +9 -5
- package/skills/building-cpp/assets/templates/projects/multi/include/greeting.h +5 -3
- package/skills/building-cpp/assets/templates/projects/multi/src/greeting.cc +18 -0
- package/skills/building-cpp/assets/templates/projects/multi/src/main.cc +8 -0
- package/skills/building-cpp/assets/templates/projects/shared-library/CMakeLists.txt +8 -3
- package/skills/building-cpp/assets/templates/projects/shared-library/greeting/CMakeLists.txt +15 -5
- package/skills/building-cpp/assets/templates/projects/shared-library/greeting/include/greeting.h +5 -3
- package/skills/building-cpp/assets/templates/projects/shared-library/greeting/src/greeting.cc +18 -0
- package/skills/building-cpp/assets/templates/projects/shared-library/src/main.cc +8 -0
- package/skills/building-cpp/assets/templates/projects/single/CMakeLists.txt +7 -3
- package/skills/building-cpp/assets/templates/projects/single/src/main.cc +15 -0
- package/skills/building-cpp/assets/templates/projects/static-library/CMakeLists.txt +8 -3
- package/skills/building-cpp/assets/templates/projects/static-library/greeting/CMakeLists.txt +15 -5
- package/skills/building-cpp/assets/templates/projects/static-library/greeting/include/greeting.h +5 -3
- package/skills/building-cpp/assets/templates/projects/static-library/greeting/src/greeting.cc +18 -0
- package/skills/building-cpp/assets/templates/projects/static-library/src/main.cc +8 -0
- package/skills/building-cpp/examples/cmake.md +17 -17
- package/skills/building-cpp/examples/environment.md +4 -3
- package/skills/building-cpp/examples/tooling.md +31 -16
- package/skills/building-cpp/references/build-script.md +2 -2
- package/skills/building-cpp/references/cmake.md +35 -17
- package/skills/building-cpp/references/environment.md +17 -13
- package/skills/building-cpp/references/linking.md +6 -6
- package/skills/building-cpp/references/standards/README.md +165 -0
- package/skills/building-cpp/references/standards/c++11/README.md +50 -0
- package/skills/building-cpp/references/standards/c++11/cmake-snippet.cmake +7 -0
- package/skills/building-cpp/references/standards/c++14/README.md +48 -0
- package/skills/building-cpp/references/standards/c++14/cmake-snippet.cmake +7 -0
- package/skills/building-cpp/references/standards/c++17/README.md +49 -0
- package/skills/building-cpp/references/standards/c++17/cmake-snippet.cmake +7 -0
- package/skills/building-cpp/references/standards/c++20/README.md +49 -0
- package/skills/building-cpp/references/standards/c++20/cmake-snippet.cmake +7 -0
- package/skills/building-cpp/references/standards/c++23/README.md +50 -0
- package/skills/building-cpp/references/standards/c++23/cmake-snippet.cmake +7 -0
- package/skills/building-cpp/references/static-analysis.md +27 -15
- package/skills/building-cpp/scripts/checking-environment.mjs +21 -21
- package/skills/building-cpp/steps/01-build.md +78 -76
- package/skills/building-cpp/steps/02-tooling.md +43 -41
- package/skills/building-cpp/steps/03-check.md +60 -60
- package/skills/developing-cpp/SKILL.md +6 -6
- package/skills/developing-cpp/examples/comments.md +10 -8
- package/skills/developing-cpp/examples/exceptions.md +64 -45
- package/skills/developing-cpp/examples/naming.md +2 -2
- package/skills/developing-cpp/examples/structure.md +12 -9
- package/skills/developing-cpp/references/comments.md +10 -8
- package/skills/developing-cpp/references/declaration-order.md +7 -4
- package/skills/developing-cpp/references/exceptions.md +83 -46
- package/skills/developing-cpp/references/glossary.md +6 -6
- package/skills/developing-cpp/references/google-cpp-style.md +27 -37
- package/skills/developing-cpp/references/language.md +4 -4
- package/skills/developing-cpp/references/layout.md +14 -14
- package/skills/developing-cpp/references/naming.md +7 -6
- package/skills/developing-cpp/references/project-design.md +3 -3
- package/skills/developing-cpp/references/standard-library.md +1 -1
- package/skills/developing-cpp/steps/02-boundary.md +7 -7
- package/skills/developing-cpp/steps/03-declaration.md +9 -8
- package/skills/developing-cpp/steps/04-implementation.md +11 -7
- package/templates/cpp-workflow-project/SKILL.md +1 -1
- package/templates/cpp-workflow-project/environment.json +2 -1
- package/skills/building-cpp/assets/templates/projects/multi/src/greeting.cpp +0 -13
- package/skills/building-cpp/assets/templates/projects/multi/src/main.cpp +0 -8
- package/skills/building-cpp/assets/templates/projects/shared-library/greeting/src/greeting.cpp +0 -13
- package/skills/building-cpp/assets/templates/projects/shared-library/src/main.cpp +0 -8
- package/skills/building-cpp/assets/templates/projects/single/src/main.cpp +0 -9
- package/skills/building-cpp/assets/templates/projects/static-library/greeting/src/greeting.cpp +0 -13
- package/skills/building-cpp/assets/templates/projects/static-library/src/main.cpp +0 -8
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
# 第 3 步:通过检查
|
|
2
|
-
|
|
3
|
-
## 产出
|
|
4
|
-
|
|
5
|
-
一次可复现的通过记录:环境校验、配置、构建、格式化、静态检查、测试、运行都通过;失败时能指出是哪一步、哪个角色、哪条诊断。
|
|
6
|
-
|
|
7
|
-
## 通用情况
|
|
8
|
-
|
|
9
|
-
按固定顺序跑,前一步失败就停,不要带着失败继续:
|
|
10
|
-
|
|
11
|
-
1. **校验环境声明(不带 `--live`)**:读 `environment.json
|
|
12
|
-
2. **活动校验**:在声明的 build host 上跑 `--live`,核对 PATH
|
|
13
|
-
3. **跑项目入口命令**:项目技能里写的入口命令(如 `./running-build.sh clang
|
|
14
|
-
4. **核对产物**:`build/<compiler>/compile_commands.json` 存在;`build/compile_commands.json` 指向当前编译器;`app` 可执行文件在 `build/<compiler>/bin`。
|
|
15
|
-
5. **记录结果**:通过时记录编译器版本、构建目录、测试数量;失败时记录命令、退出码、第一条根因诊断。
|
|
16
|
-
|
|
17
|
-
环境校验脚本:
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
node "<skill-dir>/scripts/checking-environment.mjs" --project . # 声明校验
|
|
21
|
-
node "<skill-dir>/scripts/checking-environment.mjs" --project . --live # 活动校验
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
`<skill-dir>` 换成插件里 `building-cpp` 的实际目录;不要复制脚本到项目里再改。脚本只读,不安装、不下载、不改 PATH。
|
|
25
|
-
|
|
26
|
-
## 失败分诊
|
|
27
|
-
|
|
28
|
-
| 现象 | 先看 | 回到 |
|
|
29
|
-
| --- | --- | --- |
|
|
30
|
-
| 轴为空、组合非法、版本不匹配 | `environment.json`、`--live` 输出 | 定构建,先修声明 |
|
|
31
|
-
| 找不到头文件、链接失败、target 不存在 | `CMakeLists.txt`、`target_include_directories`、`target_link_libraries` | 定构建 |
|
|
32
|
-
| 没有 `compile_commands.json`、clangd 跳转失败 | 生成器、`CMAKE_EXPORT_COMPILE_COMMANDS`、`.clangd` 路径 | 定构建 / 定工具配置 |
|
|
33
|
-
| `clang-format` 报格式 | 源码排版 | 定工具配置;只改格式,不改行为 |
|
|
34
|
-
| `clang-tidy` 报命名/类型/现代 C++ 用法 | 源码声明或实现 | `developing-cpp` 的定声明 / 定实现 |
|
|
35
|
-
| 编译错误指向声明或类型 | 头文件、类型定义、函数签名 | `developing-cpp` 的定声明 |
|
|
36
|
-
| 编译错误指向函数体 | 实现 | `developing-cpp` 的定实现;先修语义,再重跑 |
|
|
37
|
-
| CTest 失败 | 测试断言、行为句 | `developing-cpp` 的定行为 / 定实现 |
|
|
38
|
-
| `app` 启动失败、找不到共享库 | 输出目录、RPATH / 运行时库路径 | 定构建 |
|
|
39
|
-
|
|
40
|
-
分诊只定位,不自动改。一次只改一类问题;改完从失败的那一步重跑,只有行为或边界也变了才回到定行为。
|
|
41
|
-
|
|
42
|
-
## 情况
|
|
43
|
-
|
|
44
|
-
**第一次接工程**:先跑声明校验,再跑 `--live`;两者都过再跑入口命令。环境没声明对时,构建脚本再完美也会失败。
|
|
45
|
-
|
|
46
|
-
**只改源码**:仍跑完整入口命令;格式化和静态检查可能暴露声明层问题,不要只看编译通过。
|
|
47
|
-
|
|
48
|
-
**只改配置**:至少跑一次完整构建 + 格式化 + 静态检查;配置错误常常在 clangd 或 tidy 阶段才暴露。
|
|
49
|
-
|
|
50
|
-
**没有测试**:CTest 显示没有测试是合法结果;不要为了「全绿」造空测试。行为验收由定行为的验收句负责。
|
|
51
|
-
|
|
52
|
-
**Windows
|
|
53
|
-
|
|
54
|
-
**macOS**:`/usr/bin/clang++` 通常是 Apple Clang;`.clangd` 不写死 Homebrew 路径,clangd 要能经 xcrun 找到 SDK。`compiler=clang` 时 `--live` 按同一 LLVM 主版本核对 clang++、clang-format、clang-tidy、clangd;不要混用 Homebrew LLVM 与 Xcode 资源目录来凑版本,也不要为了通过而改 `environment.json` 的编译器。
|
|
55
|
-
|
|
56
|
-
## 正反例指针
|
|
57
|
-
|
|
58
|
-
- 环境组合与 `--live` 输出:`examples/environment.md`。
|
|
59
|
-
- 失败分诊的具体命令:`references/build-script.md`「失败分诊」。
|
|
60
|
-
- 工具调用细节:`references/static-analysis.md`。
|
|
1
|
+
# 第 3 步:通过检查
|
|
2
|
+
|
|
3
|
+
## 产出
|
|
4
|
+
|
|
5
|
+
一次可复现的通过记录:环境校验、配置、构建、格式化、静态检查、测试、运行都通过;失败时能指出是哪一步、哪个角色、哪条诊断。
|
|
6
|
+
|
|
7
|
+
## 通用情况
|
|
8
|
+
|
|
9
|
+
按固定顺序跑,前一步失败就停,不要带着失败继续:
|
|
10
|
+
|
|
11
|
+
1. **校验环境声明(不带 `--live`)**:读 `environment.json`,检查三个环境轴、`standard` 和组合是否合法。环境轴为空、`standard` 非法或组合非法时,停在这里,不找可执行文件。
|
|
12
|
+
2. **活动校验**:在声明的 build host 上跑 `--live`,核对 PATH 中的角色和版本。`windows` + `native` 在声明校验阶段就返回失败,不会进入这一步。
|
|
13
|
+
3. **跑项目入口命令**:项目技能里写的入口命令(如 `./running-build.sh clang`)。入口命令仍是 `<entry-command>` 或空白时,停在这里,不要猜命令;是真实命令才跑。入口内部依次 configure → build → format → tidy → ctest → run;每一步失败都保留原始输出。
|
|
14
|
+
4. **核对产物**:`build/<compiler>/compile_commands.json` 存在;`build/compile_commands.json` 指向当前编译器;`app` 可执行文件在 `build/<compiler>/bin`。
|
|
15
|
+
5. **记录结果**:通过时记录编译器版本、构建目录、测试数量;失败时记录命令、退出码、第一条根因诊断。
|
|
16
|
+
|
|
17
|
+
环境校验脚本:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
node "<skill-dir>/scripts/checking-environment.mjs" --project . # 声明校验
|
|
21
|
+
node "<skill-dir>/scripts/checking-environment.mjs" --project . --live # 活动校验
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`<skill-dir>` 换成插件里 `building-cpp` 的实际目录;不要复制脚本到项目里再改。脚本只读,不安装、不下载、不改 PATH。
|
|
25
|
+
|
|
26
|
+
## 失败分诊
|
|
27
|
+
|
|
28
|
+
| 现象 | 先看 | 回到 |
|
|
29
|
+
| --- | --- | --- |
|
|
30
|
+
| 轴为空、组合非法、版本不匹配 | `environment.json`、`--live` 输出 | 定构建,先修声明 |
|
|
31
|
+
| 找不到头文件、链接失败、target 不存在 | `CMakeLists.txt`、`target_include_directories`、`target_link_libraries` | 定构建 |
|
|
32
|
+
| 没有 `compile_commands.json`、clangd 跳转失败 | 生成器、`CMAKE_EXPORT_COMPILE_COMMANDS`、`.clangd` 路径 | 定构建 / 定工具配置 |
|
|
33
|
+
| `clang-format` 报格式 | 源码排版 | 定工具配置;只改格式,不改行为 |
|
|
34
|
+
| `clang-tidy` 报命名/类型/现代 C++ 用法 | 源码声明或实现 | `developing-cpp` 的定声明 / 定实现 |
|
|
35
|
+
| 编译错误指向声明或类型 | 头文件、类型定义、函数签名 | `developing-cpp` 的定声明 |
|
|
36
|
+
| 编译错误指向函数体 | 实现 | `developing-cpp` 的定实现;先修语义,再重跑 |
|
|
37
|
+
| CTest 失败 | 测试断言、行为句 | `developing-cpp` 的定行为 / 定实现 |
|
|
38
|
+
| `app` 启动失败、找不到共享库 | 输出目录、RPATH / 运行时库路径 | 定构建 |
|
|
39
|
+
|
|
40
|
+
分诊只定位,不自动改。一次只改一类问题;改完从失败的那一步重跑,只有行为或边界也变了才回到定行为。
|
|
41
|
+
|
|
42
|
+
## 情况
|
|
43
|
+
|
|
44
|
+
**第一次接工程**:先跑声明校验,再跑 `--live`;两者都过再跑入口命令。环境没声明对时,构建脚本再完美也会失败。
|
|
45
|
+
|
|
46
|
+
**只改源码**:仍跑完整入口命令;格式化和静态检查可能暴露声明层问题,不要只看编译通过。
|
|
47
|
+
|
|
48
|
+
**只改配置**:至少跑一次完整构建 + 格式化 + 静态检查;配置错误常常在 clangd 或 tidy 阶段才暴露。
|
|
49
|
+
|
|
50
|
+
**没有测试**:CTest 显示没有测试是合法结果;不要为了「全绿」造空测试。行为验收由定行为的验收句负责。
|
|
51
|
+
|
|
52
|
+
**Windows 原生**:本版本不支持 `host=windows` + `build_host=native`。声明校验会返回 `ok: false`,`issues` 只有一句「本版本不能在 Windows 原生壳里构建」。停在这里,不要伪造 PowerShell 脚本,不要建议改 WSL 来绕过,也不要让代理改 `environment.json` 过关。
|
|
53
|
+
|
|
54
|
+
**macOS**:`/usr/bin/clang++` 通常是 Apple Clang;`.clangd` 不写死 Homebrew 路径,clangd 要能经 xcrun 找到 SDK。`compiler=clang` 时 `--live` 按同一 LLVM 主版本核对 clang++、clang-format、clang-tidy、clangd;不要混用 Homebrew LLVM 与 Xcode 资源目录来凑版本,也不要为了通过而改 `environment.json` 的编译器。
|
|
55
|
+
|
|
56
|
+
## 正反例指针
|
|
57
|
+
|
|
58
|
+
- 环境组合与 `--live` 输出:`examples/environment.md`。
|
|
59
|
+
- 失败分诊的具体命令:`references/build-script.md`「失败分诊」。
|
|
60
|
+
- 工具调用细节:`references/static-analysis.md`。
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: developing-cpp
|
|
3
|
-
description: 编写或修改 C++
|
|
3
|
+
description: 编写或修改 C++11–C++23 源码、头文件、命名、异常与源码注释时使用;新工程默认 C++23;按定行为、定边界、定声明、定实现四步推进。一次改动同时碰到源码和构建文件时,先打开本技能。不用于只改文档、Python、CMake、构建脚本或与 C++ 无关的文件。
|
|
4
4
|
metadata:
|
|
5
|
-
short-description: C++
|
|
5
|
+
short-description: C++11–C++23 源码四步
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# developing-cpp
|
|
9
9
|
|
|
10
10
|
## 适用场景
|
|
11
11
|
|
|
12
|
-
管 `.h` / `.cpp`
|
|
12
|
+
管 `.h` / `.cc` 里换一台机器也不会改的内容:可观察行为、库与程序的边界、声明、命名、异常和源码注释。排版、命名、头文件与包含顺序以 `references/google-cpp-style.md` 的 Google 基线为准。异常条文采用 C++ Core Guidelines 的 Error handling,作为开发阶段的源码指导;它不进入插件运行时。`CMakeLists.txt`、`cmake/`、`running-build.sh`、`.clang-*`、`.vscode/` 和 `environment.json` 只开 `building-cpp`。只改函数体、命名、异常或注释且入口命令可运行时,定实现后只开 `building-cpp` 的「通过检查」;新增或移动源文件、改库与程序的边界、补测试 target 时,声明和实现可以先写,但完成前必须开 `building-cpp` 的定构建,把文件写进 CMake,再决定是否定工具配置,最后通过检查。`.qmd`、仓库 README、Python 和非 C++ 文档不打开本技能。
|
|
13
13
|
|
|
14
14
|
存在项目技能 `cpp-workflow-project` 时先读它的 `SKILL.md`:工程名、库与程序的边界、阶段表、术语增补、入口命令。没有项目技能时门禁不会放出本技能,不要猜项目约定。
|
|
15
15
|
|
|
@@ -29,7 +29,7 @@ metadata:
|
|
|
29
29
|
| 1 | 定行为 | `steps/01-behavior.md` | 把这一处要能观察到的结果写成验收句 |
|
|
30
30
|
| 2 | 定边界 | `steps/02-boundary.md` | 决定哪些放库、哪些放程序,依赖朝哪个方向 |
|
|
31
31
|
| 3 | 定声明 | `steps/03-declaration.md` | 写命名、声明顺序、头文件契约和声明注释 |
|
|
32
|
-
| 4 | 定实现 | `steps/04-implementation.md` | 写 `.
|
|
32
|
+
| 4 | 定实现 | `steps/04-implementation.md` | 写 `.cc` 的操作顺序、分组和实现注释 |
|
|
33
33
|
|
|
34
34
|
每步只打开同号的一个步骤文件。判不准才打开 `examples/` 里与该步对应的案例;`references/` 保存完整条文,只在排错、整目录重构,或步骤里明确指向某一条文时按需打开。
|
|
35
35
|
|
|
@@ -37,6 +37,6 @@ metadata:
|
|
|
37
37
|
|
|
38
38
|
- 第 1 步的行为句能被用户或测试验收;有阶段表时只覆盖对应行,没有时只覆盖用户点名的行为。
|
|
39
39
|
- 第 2 步的库 target 不依赖终端、GUI 或脚本;程序 target 只做装配和输入输出;共享抽象有第二个真实使用方。
|
|
40
|
-
- 第 3
|
|
41
|
-
- 第 4 步的实现只兑现声明;资源由 RAII
|
|
40
|
+
- 第 3 步的公共头文件自包含,命名、声明顺序和异常声明符合 `references/` 的条文。
|
|
41
|
+
- 第 4 步的实现只兑现声明;资源由 RAII 管理;失败是正常结果时用返回值,函数无法完成任务时抛异常,不拿异常做正常分支。
|
|
42
42
|
- 没有改 `CMakeLists.txt`、`.clang-*`、构建脚本,也没有把外部资料路径或项目专属类名写进通用条文。
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
**差**:
|
|
6
6
|
|
|
7
7
|
```cpp
|
|
8
|
-
// task_list.
|
|
8
|
+
// task_list.cc
|
|
9
9
|
// 作者:张三
|
|
10
10
|
// 创建:2024-01-01
|
|
11
11
|
// 修改:2024-02-01 修复 bug
|
|
@@ -43,11 +43,11 @@ Task GetTask(int index) const;
|
|
|
43
43
|
///
|
|
44
44
|
/// @param index 任务下标,必须在 [0, tasks_.size()) 内
|
|
45
45
|
/// @return 该位置的任务
|
|
46
|
-
/// @throws
|
|
46
|
+
/// @throws TaskIndexError index 越界
|
|
47
47
|
[[nodiscard]] Task GetTask(int index) const;
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
契约完整:范围、返回、异常声明。
|
|
51
51
|
|
|
52
52
|
## 实现注释
|
|
53
53
|
|
|
@@ -121,11 +121,13 @@ ColumnLimit: 100
|
|
|
121
121
|
**好**:
|
|
122
122
|
|
|
123
123
|
```yaml
|
|
124
|
-
#
|
|
125
|
-
|
|
124
|
+
# 列宽、缩进、包含顺序都取 Google 预设,不逐项覆盖。
|
|
125
|
+
Language: Cpp
|
|
126
|
+
BasedOnStyle: Google
|
|
127
|
+
Standard: Latest
|
|
126
128
|
```
|
|
127
129
|
|
|
128
|
-
|
|
130
|
+
解释为什么选预设,不写策略头,不指文档路径。
|
|
129
131
|
|
|
130
132
|
## 横幅
|
|
131
133
|
|
|
@@ -197,8 +199,8 @@ void SetPriority(TaskId id, int priority);
|
|
|
197
199
|
///
|
|
198
200
|
/// @param id 任务编号,必须已存在
|
|
199
201
|
/// @param priority 新优先级,必须在 [0, 9] 内
|
|
200
|
-
/// @throws
|
|
201
|
-
/// @throws
|
|
202
|
+
/// @throws TaskIndexError 编号不在当前任务表内
|
|
203
|
+
/// @throws InvalidPriorityError priority 越界
|
|
202
204
|
void SetPriority(TaskId id, int priority);
|
|
203
205
|
```
|
|
204
206
|
|
|
@@ -1,53 +1,95 @@
|
|
|
1
1
|
# 正反例:异常
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
这些例子只用于开发阶段讨论源码写法。插件运行时不编译它们,也不执行它们。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## 什么时候抛
|
|
6
|
+
|
|
7
|
+
**差**:用户输入格式错误是调用方每天都要处理的正常结果,却用异常表达,调用方被迫用 `try/catch` 做分支。
|
|
6
8
|
|
|
7
9
|
```cpp
|
|
8
|
-
Task ParseTask(std::string_view line); //
|
|
10
|
+
Task ParseTask(std::string_view line); // 任何格式错误都抛
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
**好**:结果类型表达可预期失败,合同违反才抛。
|
|
13
|
+
**好**:接口把「解析可能失败」写进返回类型;只有函数无法完成自己的任务、继续执行没有意义时才抛。
|
|
14
14
|
|
|
15
15
|
```cpp
|
|
16
|
-
enum class
|
|
16
|
+
enum class ParseStatus { kOk, kEmptyLine, kMissingPriority, kBadPriority };
|
|
17
17
|
|
|
18
18
|
struct ParseResult {
|
|
19
19
|
std::optional<Task> task;
|
|
20
|
-
|
|
20
|
+
ParseStatus status = ParseStatus::kEmptyLine;
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
[[nodiscard]] ParseResult TryParseTask(std::string_view line);
|
|
24
24
|
|
|
25
|
-
/// @throws
|
|
25
|
+
/// @throws TaskIndexError index 不在 [0, size()) 内。
|
|
26
26
|
[[nodiscard]] Task GetTask(int index) const;
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
`TryParseTask`
|
|
29
|
+
`TryParseTask` 把失败作为正常结果返回。`GetTask` 的前提是调用方给出有效下标;下标无效时函数无法返回一个任务,于是抛出带领域语义的 `TaskIndexError`。如果越界其实是正常输入,应该改成返回 `std::optional<Task>`,而不是让调用方捕获异常。
|
|
30
30
|
|
|
31
|
-
##
|
|
31
|
+
## 异常类型与消息
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
**差**:抛内建类型或裸字符串,调用方只能捕获一切。
|
|
34
34
|
|
|
35
35
|
```cpp
|
|
36
|
-
throw
|
|
36
|
+
throw "bad index";
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
**好**:定义有语义的类型;确实没有更多信息时,才直接用标准库通用类型。
|
|
40
40
|
|
|
41
41
|
```cpp
|
|
42
|
-
|
|
42
|
+
class TaskIndexError : public std::out_of_range {
|
|
43
|
+
public:
|
|
44
|
+
explicit TaskIndexError(const std::string& message)
|
|
45
|
+
: std::out_of_range(message) {}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
throw TaskIndexError{
|
|
43
49
|
std::format("GetTask: index={} 超出 [0, {})", index, tasks_.size())};
|
|
44
50
|
```
|
|
45
51
|
|
|
46
|
-
|
|
52
|
+
消息写操作和关键值,不写「出错了」;`std::format` 只是构造消息的方式,不强制固定模板。
|
|
53
|
+
|
|
54
|
+
## 多语义类型:Boost.Exception 风格
|
|
55
|
+
|
|
56
|
+
一个错误可以同时属于多个类别。类型只做 `catch` 的标签,数据由基类或错误信息容器携带;多继承时用 virtual 基类,避免 `catch (const std::exception&)` 二义性。
|
|
57
|
+
|
|
58
|
+
```cpp
|
|
59
|
+
struct exception_base : virtual std::exception, virtual boost::exception {};
|
|
60
|
+
struct io_error : virtual exception_base {};
|
|
61
|
+
struct file_error : virtual io_error {};
|
|
62
|
+
struct read_error : virtual io_error {};
|
|
63
|
+
struct file_read_error : virtual file_error, virtual read_error {};
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
这只是设计典范,不要求引入 Boost。项目自己的异常层级也可以照这个形状写。
|
|
67
|
+
|
|
68
|
+
## 捕获
|
|
69
|
+
|
|
70
|
+
**差**:捕获一切后静默返回,状态可能已经半坏。
|
|
71
|
+
|
|
72
|
+
```cpp
|
|
73
|
+
try {
|
|
74
|
+
Load(path);
|
|
75
|
+
} catch (...) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**好**:只捕获当前层能处理的类型;不能处理的继续传播。`catch` 从派生到基类排序,`catch (...)` 只能最后兜底。
|
|
81
|
+
|
|
82
|
+
```cpp
|
|
83
|
+
try {
|
|
84
|
+
Load(path);
|
|
85
|
+
} catch (const FileReadError& error) {
|
|
86
|
+
return LoadResult::kNotFound;
|
|
87
|
+
}
|
|
88
|
+
```
|
|
47
89
|
|
|
48
90
|
## 边界
|
|
49
91
|
|
|
50
|
-
|
|
92
|
+
**差**:库代码捕获后打印并吞掉异常。
|
|
51
93
|
|
|
52
94
|
```cpp
|
|
53
95
|
void AddTask(Task task) {
|
|
@@ -59,10 +101,9 @@ void AddTask(Task task) {
|
|
|
59
101
|
}
|
|
60
102
|
```
|
|
61
103
|
|
|
62
|
-
|
|
104
|
+
**好**:库让异常向上传播,入口统一翻译成用户可读的诊断。
|
|
63
105
|
|
|
64
106
|
```cpp
|
|
65
|
-
// main.cpp
|
|
66
107
|
int main() {
|
|
67
108
|
try {
|
|
68
109
|
return Run(std::cin, std::cout);
|
|
@@ -73,29 +114,7 @@ int main() {
|
|
|
73
114
|
}
|
|
74
115
|
```
|
|
75
116
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
**差**:
|
|
79
|
-
|
|
80
|
-
```cpp
|
|
81
|
-
try {
|
|
82
|
-
Load(path);
|
|
83
|
-
} catch (...) {
|
|
84
|
-
return; // 不知道发生了什么,状态可能半坏
|
|
85
|
-
}
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
**好**:
|
|
89
|
-
|
|
90
|
-
```cpp
|
|
91
|
-
try {
|
|
92
|
-
Load(path);
|
|
93
|
-
} catch (const std::filesystem::filesystem_error& error) {
|
|
94
|
-
return LoadResult::kNotFound;
|
|
95
|
-
}
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
只捕获能处理的类型;其他异常继续抛。
|
|
117
|
+
退出码由项目入口合同决定;这里只示范「捕获、打印、非零返回」。
|
|
99
118
|
|
|
100
119
|
## 析构
|
|
101
120
|
|
|
@@ -121,13 +140,13 @@ try {
|
|
|
121
140
|
|
|
122
141
|
## `std::format` 与 `std::print`
|
|
123
142
|
|
|
124
|
-
C++
|
|
143
|
+
C++23 且标准库支持 `std::print` 时,程序入口或 CLI 可以写:
|
|
125
144
|
|
|
126
145
|
```cpp
|
|
127
|
-
std::print("任务: {}\n", task.name);
|
|
146
|
+
std::print("任务: {}\n", task.name);
|
|
128
147
|
```
|
|
129
148
|
|
|
130
|
-
|
|
149
|
+
库代码、以及需要兼容 C++11–C++20 的代码仍写:
|
|
131
150
|
|
|
132
151
|
```cpp
|
|
133
152
|
std::cout << std::format("任务: {}\n", task.name);
|
|
@@ -103,12 +103,12 @@ namespace string_utils { // 一组自由函数
|
|
|
103
103
|
**好**:
|
|
104
104
|
|
|
105
105
|
```cpp
|
|
106
|
-
[[nodiscard]] const Task& GetTask(std::string_view name) const; // 找不到抛
|
|
106
|
+
[[nodiscard]] const Task& GetTask(std::string_view name) const; // 找不到抛 TaskNotFoundError
|
|
107
107
|
[[nodiscard]] const Task* FindTask(std::string_view name) const; // 找不到返回 nullptr
|
|
108
108
|
[[nodiscard]] bool HasTask(std::string_view name) const; // 只回答存在性
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
-
`Get`
|
|
111
|
+
`Get` 表示结果一定存在(否则抛出声明过的领域异常),`Find` 表示可能找不到,`Has` / `Contains` 只回答是否存在。不要用 `Find` 返回 `bool`。
|
|
112
112
|
|
|
113
113
|
## 谓词与 Lambda
|
|
114
114
|
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
**差**:库函数直接打印,程序只调用它。
|
|
21
21
|
|
|
22
22
|
```cpp
|
|
23
|
-
// task_list.
|
|
23
|
+
// task_list.cc(库)
|
|
24
24
|
void TaskList::Print() const {
|
|
25
25
|
for (const auto& task : tasks_) {
|
|
26
26
|
std::cout << task.priority << " " << task.name << "\n";
|
|
@@ -36,7 +36,7 @@ void TaskList::Print() const {
|
|
|
36
36
|
// task_list.h(库)
|
|
37
37
|
[[nodiscard]] std::vector<Task> SortedByPriority() const;
|
|
38
38
|
|
|
39
|
-
// app/cli.
|
|
39
|
+
// app/cli.cc(程序)
|
|
40
40
|
void PrintTasks(const std::vector<Task>& tasks, std::ostream& out) {
|
|
41
41
|
for (const auto& task : tasks) {
|
|
42
42
|
out << std::format("{} {}\n", task.priority, task.name);
|
|
@@ -50,29 +50,32 @@ void PrintTasks(const std::vector<Task>& tasks, std::ostream& out) {
|
|
|
50
50
|
|
|
51
51
|
**差**:
|
|
52
52
|
|
|
53
|
-
```cpp
|
|
54
|
-
#include "task_list/task_list.h" // 公共根下又套一层组件名
|
|
55
|
-
```
|
|
56
|
-
|
|
57
53
|
```text
|
|
58
54
|
src/task_list.h // 公共头藏在 src,测试无法只依赖公共接口
|
|
55
|
+
src/detail.h // 私有头被测试直接包含
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```cpp
|
|
59
|
+
#include "src/task_list.h" // 从仓库根写到了实现目录
|
|
59
60
|
```
|
|
60
61
|
|
|
61
62
|
**好**:
|
|
62
63
|
|
|
63
64
|
```text
|
|
64
65
|
task_list/include/task_list.h // 公共头
|
|
65
|
-
task_list/src/task_list.
|
|
66
|
+
task_list/src/task_list.cc // 实现
|
|
66
67
|
task_list/src/detail.h // 私有头,只被本组件包含
|
|
67
68
|
```
|
|
68
69
|
|
|
69
70
|
```cpp
|
|
70
|
-
#include "task_list.h"
|
|
71
|
+
#include "task_list/include/task_list.h" // 从源码根写公共头的完整路径
|
|
71
72
|
```
|
|
72
73
|
|
|
74
|
+
构建时把仓库根加入 include 搜索路径;不要用 `#include "../task_list/include/task_list.h"` 这种随文件位置漂移的写法。
|
|
75
|
+
|
|
73
76
|
## 单文件何时拆库
|
|
74
77
|
|
|
75
|
-
**先不拆**:一个 `main.
|
|
78
|
+
**先不拆**:一个 `main.cc`,辅助函数在匿名命名空间,只有程序自己用。
|
|
76
79
|
|
|
77
80
|
**该拆**:测试需要直接调用排序逻辑;或第二个程序要复用同一逻辑;或逻辑已经超过一个屏幕。
|
|
78
81
|
|
|
@@ -28,11 +28,11 @@
|
|
|
28
28
|
//===----------------------------------------------------------------------===//
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
- 横幅宽度固定
|
|
31
|
+
- 横幅宽度固定 80 列;`//` 后 3 个 `=`,中间 70 个 `-`,末尾 `===//`。
|
|
32
32
|
- 横幅只包住逻辑组,不包住单个函数;函数之间用空行,不用横幅。
|
|
33
|
-
- 脚本里用 `#===` 形式,宽度同样
|
|
33
|
+
- 脚本里用 `#===` 形式,宽度同样 80 列;CMake 用 `#---` 小节即可,不用重横幅。
|
|
34
34
|
- 一个文件不超过 8 个横幅;超过说明文件该拆了。
|
|
35
|
-
-
|
|
35
|
+
- 80 列换行分三类:整句在标点处断;参数/返回值列表每项一行;代码示例保持原样,宁可横向滚动也不在半句断开。
|
|
36
36
|
|
|
37
37
|
## 声明注释
|
|
38
38
|
|
|
@@ -43,14 +43,14 @@
|
|
|
43
43
|
///
|
|
44
44
|
/// @param id 任务编号,必须在 [0, kTaskCount) 内
|
|
45
45
|
/// @return 该编号的任务状态
|
|
46
|
-
/// @throws
|
|
46
|
+
/// @throws TaskIndexError id 越界
|
|
47
47
|
[[nodiscard]] TaskState GetTaskState(int id) const;
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
- 第一行一句话说清「做什么」,空一行后写参数、返回值、异常。
|
|
51
51
|
- `@param` 要么全写,要么全不写;只有一个参数且含义自明时可以省略。
|
|
52
52
|
- `@return` 在返回类型自明时省略;`[[nodiscard]]` 已经表达「必须使用」时不要再写一遍。
|
|
53
|
-
- `@throws` 必须和 `references/exceptions.md`
|
|
53
|
+
- `@throws` 必须和 `references/exceptions.md` 的异常声明一致;不抛的函数不要写。
|
|
54
54
|
- 禁止 `@todo`、`@fixme`、`@author`、`@since`;待办统一用下面的 TODO 格式。
|
|
55
55
|
- 枚举值的尾随注释用 `///<`,全部值都写或全部不写,并对齐;语义结果写在最前,编号或内部值写在后面。
|
|
56
56
|
- 私有声明同样写合同:调用者可能是同一个类的另一个成员,不能假设它知道所有前置条件。
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
|
|
60
60
|
## 实现注释
|
|
61
61
|
|
|
62
|
-
`.
|
|
62
|
+
`.cc` 里的注释只写「为什么」和「这里有什么坑」,不复述语句。
|
|
63
63
|
|
|
64
64
|
```cpp
|
|
65
65
|
// 先判空再取首元素:空订单列表是合法状态,不能假设至少有一单。
|
|
@@ -103,8 +103,10 @@ if (orders_.empty()) {
|
|
|
103
103
|
`.clang-format`、`.clang-tidy`、`.clangd`、CMake 的配置项旁边写「为什么这样设」,不写「这一项是什么」。
|
|
104
104
|
|
|
105
105
|
```yaml
|
|
106
|
-
#
|
|
107
|
-
|
|
106
|
+
# 列宽、缩进、包含顺序都取 Google 预设,不逐项覆盖。
|
|
107
|
+
Language: Cpp
|
|
108
|
+
BasedOnStyle: Google
|
|
109
|
+
Standard: Latest
|
|
108
110
|
```
|
|
109
111
|
|
|
110
112
|
- 配置注释贴在被解释的键上方,不写大段策略头。
|
|
@@ -44,7 +44,8 @@ class TaskTable {
|
|
|
44
44
|
## 命名空间作用域的头文件
|
|
45
45
|
|
|
46
46
|
```cpp
|
|
47
|
-
#
|
|
47
|
+
#ifndef TASKFLOW_INCLUDE_TASK_TABLE_H_
|
|
48
|
+
#define TASKFLOW_INCLUDE_TASK_TABLE_H_
|
|
48
49
|
|
|
49
50
|
#include <array>
|
|
50
51
|
#include <cstdint>
|
|
@@ -72,15 +73,17 @@ class TaskTable {
|
|
|
72
73
|
};
|
|
73
74
|
|
|
74
75
|
} // namespace taskflow
|
|
76
|
+
|
|
77
|
+
#endif // TASKFLOW_INCLUDE_TASK_TABLE_H_
|
|
75
78
|
```
|
|
76
79
|
|
|
77
80
|
顺序:包含 → 命名空间 → `inline constexpr` 常量 → `enum class` → `struct`(被依赖的在前)→ 自由函数 → 类。类的公共接口类型放在类内最前。
|
|
78
81
|
|
|
79
|
-
## `.
|
|
82
|
+
## `.cc` 的定义顺序
|
|
80
83
|
|
|
81
84
|
- 与头文件声明同序:先类型和常量,再自由函数,再成员函数;成员函数按类内声明顺序。
|
|
82
|
-
- 文件头注释之后先放本文件的 `namespace taskflow {
|
|
83
|
-
- 构造函数、析构函数、拷贝/移动定义放在成员函数组的最前;`= default` 的定义放 `.
|
|
85
|
+
- 文件头注释之后先放本文件的 `namespace taskflow {`,再放公共定义;不需要外部引用的实现放匿名命名空间,或声明 `static`;按是否需要内部链接选择,不要为了「整洁」强行加。
|
|
86
|
+
- 构造函数、析构函数、拷贝/移动定义放在成员函数组的最前;`= default` 的定义放 `.cc` 时紧跟声明顺序。
|
|
84
87
|
- 不要为了「先编译」重排定义;C++ 不要求定义顺序,读者顺序优先。
|
|
85
88
|
|
|
86
89
|
## 空行
|