diff --git a/.agents/docs/2026-07-19-mcpp-replace-xmake-research.md b/.agents/docs/2026-07-19-mcpp-replace-xmake-research.md new file mode 100644 index 0000000..3438368 --- /dev/null +++ b/.agents/docs/2026-07-19-mcpp-replace-xmake-research.md @@ -0,0 +1,416 @@ +# 调研报告:用 mcpp 替代 xmake 支撑 d2mcpp 全项目 + +- 日期:2026-07-19 +- 范围:d2mcpp(课程仓库)、d2x(课程驱动 CLI)、mcpp 0.0.99(构建工具) +- 结论一句话:**当前不可整体替换;但经 §4 的 rustlings/cargo 对照修订后,真正的阻塞只剩 1 个——mcpp 的 `[package].standard` 不接受 c++11/14/17/20。推荐"按标准分 workspace member(5~10 个)+ 每 member 内多 target + ninja 逐 target 隔离"。** +- ⚠️ 阅读顺序:§1-§3 是初版结论(单包 155 target、3 个上游需求);**§4 基于 rustlings/cargo 的横向对照做了架构修订,以 §4.4 为准。** + +--- + +## 1. 现状:xmake 在 d2mcpp 里承担什么 + +### 1.1 集成缝在哪 + +d2mcpp 不直接暴露 xmake 给学习者。三个 README 里 `xmake` 出现 **0 次**,学习者的唯一入口是 `d2x checker`。xmake 通过一层薄适配器接入: + +``` +.d2x.json: "buildtools": "xmake d2x-buildtools" + ↓ +xmake.lua:1 add_plugindirs("d2x/buildtools") + ↓ +d2x/buildtools/xmake/{xmake.lua, main.lua} ← 实现 init / list / build / run +``` + +契约写在 `d2x/buildtools/README.md`,只有 4 个命令。d2x 侧的实现(`d2x/src/buildtools.cppm:28-42`)是裸字符串拼接 + `popen`: + +```cpp +auto init() const { return platform::run_command_capture(bin + " init"); } +auto list() const { return platform::run_command_capture(bin + " list"); } +auto build(const std::string& t) const { return platform::run_command_capture(bin + " build " + t); } +auto run (const std::string& t) const { return platform::run_command_capture(bin + " run " + t); } +``` + +`bin` 完全来自配置,**不限定是 xmake**——写成 `./d2x/buildtools/mcpp/adapter` 也能跑。这是好消息:适配器不需要 mcpp 提供插件机制。 + +### 1.2 契约的精确要求(迁移必须逐条满足) + +| 项 | 要求 | 出处 | +|---|---|---| +| `list` 输出 | 每行 `@ <绝对路径>, <绝对路径>...`,`@` 必须**恰好出现一次**,否则该行被**静默丢弃** | `d2x/src/buildtools.cppm:76-100` | +| 路径 | 事实上必须绝对(`utils::read_file_to_string` 会抛异常,编辑器打开、mtime 轮询都按 CWD 解析) | `d2x/src/utils.cppm:66` 的 TODO | +| 排序 | 存进 `std::map`,即**按 target 名字典序**决定练习顺序 | `buildtools.cppm:21` | +| 退出码 | `build`/`run` 必须 `exit == 0` 才算通过;不解析编译器错误文本 | `d2x/src/checker.cppm:18-26` | +| 通过判定 | build==0 **且** run==0 **且** 输出无 `❌` **且** 无 `D2X_WAIT` | `checker.cppm:80-127` | +| 环境 | d2x 调用前会**清空 `LD_LIBRARY_PATH`**,且从不 `chdir` | `d2x/src/platform.cppm:51-54` | +| 噪声容忍 | 不匹配的行被忽略;ANSI 转义会被 trim 掉 | `d2x/src/utils.cppm:32-56` | + +`init` 会在 `load_buildtools()` 里被**无条件调用一次且忽略返回值**(`buildtools.cppm:109`),mcpp 适配器可以让它做真正的初始化工作而不怕失败传播。 + +### 1.3 target 全景(迁移工作量的真实分母) + +11 个 `xmake.lua`,153 处 target 声明。实际参与构建的只有两套之一(zh / en 互斥,同名): + +| lang | target 数 | 组成 | +|---|---|---| +| `en`(`option` 默认,且是提交进仓库的 `.d2x.json` 值) | 51 | 1 hello + 48 en/cpp11 + 2 en/cpp14 | +| `zh` | 52 | 1 hello + 49 cpp11 + 2 cpp14 | + +- **`dslings/cpp17`、`cpp20`、`cpp23` 全是 6 字节的 README 占位符**,0 个 `.cpp`,没有任何 `includes()` 引用。课程实际只写到 cpp11 + 2 个 cpp14 练习。 +- **`solutions/` 51 个 `-ref` target 完全没被构建**——`xmake.lua:6` 的 `includes("solutions/xmake.lua")` 被注释掉了(commit `307dc8a`)。 +- **每个 target 都是"一个 `.cpp`、无依赖"**:`add_files` 带多文件/通配符 = 0 处,`add_deps`/`add_packages`/`add_defines`/`add_rules`/自定义 hook = 0 处。这是迁移最有利的事实。 + +需要特殊处理的只有 **32 个 target**(占 152 的 21%),且模式极少: + +| 特性 | 出现次数 | 涉及 target | +|---|---|---| +| `set_kind("binary")`(显式,语义上是默认值,可直接丢弃) | 23 | 各 dir 前几个 | +| `add_cxxflags("-fno-elide-constructors")` + `set_optimize("none")` | 3 | `04-rvalue-references` ×{zh,en,sol} | +| `add_cxxflags("-Wpedantic -Werror")` | 3 | `07-constexpr-0` ×{zh,en,sol} | +| 单 target `set_languages("c++17")` | 3 | `08-literal-type-0` ×{zh,en,sol} | +| 单 target `set_languages("cxx11")` | 2 | `00-0-hello-mcpp` ×{zh,en} | +| 文件级 `set_languages` | 7 个文件 | — | +| Windows 分支(`set_encodings` / `set_toolchains("gcc")` / `add_ldflags("-static")`) | 1 处 | `dslings/xmake.lua:1-5` | +| `add_includedirs(".")` | 1 处(根) | **155/155 个 `.cpp` 都靠它** `#include ` | + +--- + +## 2. mcpp 能力核对(含实测) + +以下带 ✅/❌ 的结论**均为本机 mcpp 0.0.99 实测**,非仅读文档。 + +### 2.1 能做到的 + +**✅ 单包多可执行 target。** `[targets.] kind="bin" main="..."`,每个 target 的 `main` 对其他 target 是排除的(`src/build/plan.cppm:882-895`),155 个各带 `main()` 的文件不会 `multiple definition`。实测 3 target 一次构建出 3 个二进制。 + +**✅ 扁平布局,零文件搬迁。** 不需要 `src/` 目录,`main` 可指向包根下任意相对路径: + +```toml +[build] +sources = ["*.cpp"] + +[targets.ex0] +kind = "bin" +main = "00-auto-and-decltype-0.cpp" +``` +实测通过。dslings 现有目录结构可以原地不动。 + +**✅ 每 target 编译选项。** `cxxflags` / `cflags` / `defines` 可用。文档警告"只作用于该 target 的入口 TU"——但对"一个练习 = 一个 `.cpp`"的场景,入口 TU **就是**整个程序,所以 `-fno-elide-constructors`、`-Wpedantic -Werror`、`-O0` 全部覆盖到位。这三个特殊 target 无损迁移。 + +**✅ 非模块的普通 C++ 能构建。** `import std` 的 BMI 预构建是条件触发的(`src/build/prepare.cppm:3176-3217`),155 个无 `import` 的普通 `.cpp` 走快速路径。 + +**✅ 退出码符合 d2x 契约。** 实测:正常构建 0 / 编译失败 1 / 成员不存在 2 / `run` 0。 + +**✅ 速度显著优于 xmake。** 同机实测: + +| 操作 | xmake | mcpp | +|---|---|---| +| 列出 target | **2.06 s** | — (无此命令) | +| 单练习构建(冷) | 0.63 s | **0.12 s** | +| 单练习构建(暖,无改动) | 0.61 s | **0.014 s** | + +xmake 每次都要付 Lua VM 启动成本,暖构建几乎不省。mcpp 暖路径 14 ms —— 对 `d2x checker` 这种"改一行、立刻重编"的循环,这是量级差异。 + +**✅ 自带工具链沙箱。** 这正是 d2x 自己迁到 mcpp 时解决 macOS SDK 问题的关键。同时能一并解掉 CI 里那条已知的坑:d2x 的 `checker-smoke` job 注释写着 *"d2mcpp 的 .xlings.json 钉了 xmake 3.0.7,它已从 registry 移除,所以 xlings 的 xmake shim 会解析失败"*(`d2x/.github/workflows/ci.yml:124-134`)。迁到 mcpp 后这个 workaround 可以整个删掉。 + +**✅ Windows 覆盖更好。** MinGW(`x86_64-windows-gnu`)与 MSVC(`msvc@system`,0.0.90 起)都支持,且默认 `static_stdlib = true`——正好对上 d2x 会清空 `LD_LIBRARY_PATH` 的行为,比现在手写 `add_ldflags("-static")` 更稳。 + +### 2.2 阻塞点 + +**🚨 阻塞 1:C++ 标准下限是 c++23。** + +``` +$ mcpp build # mcpp.toml 里 standard = "c++11" +error: unsupported C++ standard 'c++11'; expected c++23, c++26, c++2c, + gnu++23, gnu++26, c++latest, or c++fly +``` + +白名单硬编码在 `mcpp/src/manifest/types.cppm:539-586`。所有绕行通道都被显式堵死: + +``` +$ # [targets.X].cxxflags = ["-std=c++11"] +error: targets.ex-c.cxxflags contains '-std=c++11'; use [package].standard + to configure the C++ language standard +``` +(`[build].cxxflags` 同样有此守卫,见 `toml.cppm:830-836`。) + +对一个**以 C++ 标准分级为组织主轴**的课程仓库(`cpp11/` `cpp14/` `cpp17/` `cpp20/` `cpp23/`),这是根本性冲突。 + +**这有多严重?我做了量化实测**:把 51 个 `solutions/` 全部在"原标准"与 c++23 下编译并 diff 运行输出(地址已归一化): + +``` +identical output : 50 +DRIFTED : 1 ← 04-rvalue-references +``` + +好消息:**50/51 无差异**,短期风险比预想的低。坏消息:**漂移的那一个恰好是移动语义的核心课**。C++11 下: + +``` +----> 临时对像 - 右值2 +Object():0x...60c +Object(Object&&):0x...608 ← 移动构造,整节课的教学点 +~Object():0x...60c +``` + +C++23 下(同样带 `-fno-elide-constructors`): + +``` +----> 临时对像 - 右值2 +Object():0x...de8 ← 只剩这一行 +``` + +因为 C++17 的**保证复制省略**让 `-fno-elide-constructors` 无法再强制 prvalue 实质化。教学内容被标准升级**直接抹掉**,而不是"编译失败"这种能被 CI 发现的显式故障。随着课程往 cpp17/20 扩写,这类静默漂移只会变多。 + +顺带确认:`07-constexpr-0` 的 `-Wpedantic -Werror` 守卫(VLA 报错)在两个标准下**都成立**(各 3 个 error),这个练习无损。 + +**❌ 阻塞 2:`mcpp build ` 不能按 target 过滤。** + +`build` 子命令**没有位置参数**(`src/cli.cppm:217-241`),传进去的名字被静默忽略,永远全量构建。实测:`rm -rf target && mcpp build ex-a` → 三个二进制全出来了。(`-p/--package` 选的是 workspace 成员,不是 target;`--target` 是**平台三元组**,不是 target 名。`mcpp run ` 倒是支持。) + +这与 dslings 的语义直接冲突:**练习本来就该是编译不过的**(`D2X_YOUR_ANSWER` 宏展开为空,49 个练习带该标记)。实测单包场景: + +``` +$ mcpp build # 3 个 target,其中 1 个坏 +error: build failed +... +$ ls target/.../bin/ # 空 +``` + +一个坏兄弟拖垮整包、且**一个产物都不出**。 + +**❌ 阻塞 3:没有列 target 的命令,更没有机器可读输出。** + +全 CLI 22 个命令里没有 `list`/`targets`/`metadata`。唯一的 `--json` 是 `mcpp xpkg parse --json`。最接近的是 `target/.build_cache` 里的纯文本 `runTargets=` 块。d2x 的 `list` 契约无法直接满足。 + +### 2.3 阻塞 2 有一个可用的逃生舱 + +mcpp 后端是 ninja,且 **`build.ninja` 在构建失败时依然会生成**。实测(`ex-b` 故意写坏,先 `mcpp build` 失败退出 1,再清空产物只留 `build.ninja`): + +``` +1) mcpp build (all, b broken) exit=1 +2) 清空 bin/ 和 obj/,保留 build.ninja +3) ninja bin/ex-a exit=0 → bin/ 里出现 ex-a +4) ninja bin/ex-c exit=0 → bin/ 里出现 ex-c +5) ninja bin/ex-b exit=1 (坏的那个,正确失败) +6) 最终 bin/: ex-a ex-c +``` + +**逐 target 隔离 + 正确退出码,完全满足 d2x 契约。** `ninja -t targets` 还能直接枚举出 `bin/ex-a: cxx_link` 这样的列表,可以作为 `list` 命令的数据源之一。 + +代价:适配器要依赖 mcpp 的内部产物布局(`target///build.ninja`,路径含哈希,需 `find` 定位)和一个 ninja 可执行文件。**这是耦合内部实现,属于技术债,应该同时向上游提需求。** + +### 2.4 workspace 方案为什么不推荐 + +workspace 能天然隔离失败(实测 `mcpp build -p a` 在兄弟成员坏掉时正常返回 0),但代价过高: + +- **members 不支持 glob**——`docs/06-workspace.md:34` 写了 `members = ["libs/*"]`,**实测报错** `workspace member 'a' not found in [workspace].members`。解析器逐字符串比较(`src/project.cppm:40`)。155 个练习要在根清单里手写 155 条字面路径。**这是文档 bug,值得单独给 mcpp 提 issue。**(另:`workspace.exclude` 被解析后**从未被读取**,是死配置。) +- 每个成员要独立 `mcpp.toml` + 独立 `target/` 目录 → 155 个清单、155 个构建目录。 +- **workspace 根的 `[build]` 不被成员继承**——实测根上写 `include_dirs` 成员读不到,155 个成员每个都得重复写 `include_dirs = ["../../.."]`。 +- **成员构建是串行的**(`src/cli/cmd_build.cppm:65-74` 是普通 `for` 循环,每个成员完整走一遍 `prepare_build` + spawn ninja)。 + +--- + +## 3. 结论与建议 + +### 3.1 直接回答 + +**"除去 xmake、用 mcpp 支撑整个项目"——今天做不到。** 卡在三点:C++ 标准下限、无按 target 构建、无 target 枚举。其中第 2、3 点有 workaround(ninja 直连),**第 1 点没有 workaround**,必须改 mcpp。 + +但三点的修复成本都不高,而且第 1 点的修复位置非常明确、局部。 + +### 3.2 推荐路线:单包多 target + ninja 直连,分三阶段 + +> ⚠️ **本节已被 §4(rustlings/cargo 对照)修订。** 布局从"单包 155 target"改为"**按标准分 workspace member**",上游需求从 3 个降为 1 个必需 + 2 个可选。下面的阶段划分仍然成立,但请以 §4.4 的架构为准。 + +**阶段 0 — 先给 mcpp 提上游需求**(这是关键路径,其余都在等它) + +| # | 需求 | 位置 | 估计改动 | +|---|---|---|---| +| 1 | **【必需】** `[package].standard` 放宽到 `c++11/14/17/20`(含 `gnu++` 变体) | `mcpp/src/manifest/types.cppm:520-586` 的 `normalize_cpp_standard` | ~30 行,纯新增分支。已确认 `[language].modules must be true` 的守卫(`toml.cppm:146-149`)**只在出现废弃的 `[language]` 段时才触发**(`had_language_section`),对源码无硬约束,不构成架构冲突 | +| 2 | 【可选】`mcpp build ` 按 target 名过滤(对齐已有的 `mcpp run `) | `mcpp/src/cli.cppm:217-241` 加位置参数 + `src/build/execute.cppm` 过滤 link unit | 小。有 ninja 兜底 | +| 3 | 【可选】`mcpp list --json`(或 `mcpp targets`)输出 target 名 + 源文件列表 | 新增子命令,数据已在 plan 里 | 小。有 `ninja -t targets` 兜底 | + +附带值得报的两个 bug:workspace `members` glob 文档与实现不符(cargo 同款语法可用,mcpp 报错);`workspace.exclude` 是死代码。 + +> ❌ **不要提"per-target `standard`"这个需求。** 我一度打算这么提(对齐 cargo 的 per-`[[bin]]` `edition`),但实测发现 **cargo 正在废弃该字段**:`warning: 'edition' is set on binary 'ex-c' which is deprecated`。cargo 官方文档标注其"将在未来 Edition 移除"。语言版本的正确粒度是**包**,不是 target。详见 §4.3。 + +**阶段 1 — 在 d2mcpp 侧写 mcpp 适配器**(可与阶段 0 并行) + +- 新建 `d2x/buildtools/mcpp/`,与现有 `xmake/` 平级(`cmake/README.md` 早就占了位,内容只有 `TODO`——说明多适配器一直在规划里)。 +- 用生成器从 `dslings/**/*.cpp` 生成 `mcpp.toml`(155 个 `[targets.*]`,扁平布局,零文件搬迁)。生成器要处理的特殊情况只有 32 个 target、5 种模式,全部可枚举。 +- 适配器实现四个命令: + - `init` → `mcpp build`(忽略失败,目的是刷新 `build.ninja`) + - `list` → `ninja -t targets` 或直接读生成器的映射表,输出 `name@ /abs/path` + - `build ` → 上游需求 2 落地前用 `ninja -C bin/`,落地后换成 `mcpp build ` + - `run ` → `mcpp run ` +- 注意三个坑:**target 名要 shell 安全**(d2x 不做转义);**路径必须绝对**;**名字里不能有 `@`**(会让整行被静默丢弃)。 +- 命名要保持字典序 = 教学顺序(d2x 用 `std::map`)。 + +**阶段 2 — 切换与收尾** + +- `.d2x.json` 的 `buildtools` 改指向 mcpp 适配器;`.xlings.json` 去掉 `xmake` 与 `gcc`/`mingw-w64` 的 pin,换成 `mcpp`(mcpp 自带工具链)。 +- 删掉 `dslings/xmake.lua:1-5` 的 Windows 分支(mcpp 默认静态链接 + 自带 MinGW/MSVC 覆盖)。 +- d2x 的 `checker-smoke` CI job 可以删掉"用真 xmake 而非 xlings shim"的 workaround。 +- **`add_includedirs(".")` 对应 `[build] include_dirs = ["."]`** ——155/155 个文件全靠它,别漏。 + +### 3.3 阶段 0 完成前的过渡建议 + +- **不要现在就把 dslings 迁到 mcpp。** 强行迁移意味着把 cpp11 课程按 c++23 编译,`04-rvalue-references` 的教学内容会**静默失效**(不是编译报错,CI 抓不到)。 +- **可以现在就用 mcpp 的地方**:未来的 `dslings/cpp23/`。那个目录现在是空占位,而 C++23 模块教学本来就该用 mcpp(`d2x/mcpp/common.cppm` 已经放了一个 `export module d2x.project.common;` 的桩)。以它为试点验证适配器,零迁移风险。 + - ⚠️ 但那个桩现在是坏的:`#include` 在全局模块片段里且什么都没 `export`,而**宏本来就不能跨模块导出**——`import d2x.project.common;` 拿不到 `d2x_assert` 也拿不到 `D2X_WAIT`,即拿不到 d2x 的整个判定协议。cpp23 章节要么继续 `#include` 那个头,要么把断言重新设计成非宏形式。这需要先决策。 +- 注意 d2x 目前**只支持单一 `buildtools` 配置**。若要 cpp11-20 留 xmake、cpp23 用 mcpp,需要适配器内部按目录路由,或给 d2x 加多 buildtools 支持。**前者更简单,建议走前者。** + +### 3.4 顺带发现的既有问题(与迁移无关,但建议一并修) + +1. **`dslings-ref-ci.yml` 是个静默空转的 CI。** 它只挑 `-ref` 结尾的 target,而 `solutions/` 在 `xmake.lua:6` 被注释掉了 → grep 返回空 → 循环全跳过 → job 退出 0。第 60 行的 `wc -l` 对空串仍打印 "Found 1 reference targets",把空转掩盖了。**参考答案实际上没有任何 CI 校验。** +2. **`dslings/en/cpp11/xmake.lua` 少一个 target**:`00-auto-and-decltype-5.cpp` 文件在但没有 target(49 文件 / 48 target)。 +3. **命名不一致**:dslings 用 `cpp11-00-auto-and-decltype`(无 `-0`),solutions 用 `cpp11-00-auto-and-decltype-0-ref`。迁移生成器必须处理。 +4. **`solutions/xmake.lua` 没有 Windows 分支**,若重新启用会在 Windows 上缺 UTF-8/gcc/静态链接处理。 +5. **`d2x/src/checker.cppm:74-76` 无 `files.empty()` 保护**就索引 `files[0]`——某个 target 若列出零文件会崩。`d2x/docs/crash-analysis-d2x-in-d2mcpp.md:52` 声称加过保护,实际没有。 + +--- + +## 附:能力对照速查 + +| 需求 | xmake(现状) | mcpp 0.0.99 | 迁移后 | +|---|---|---|---| +| 155 个单文件可执行 | ✅ | ✅ `[targets.*]` | ✅ | +| 零文件搬迁(扁平布局) | ✅ | ✅ 实测 | ✅ | +| 每 target 编译选项 | ✅ | ✅ `cxxflags`/`defines` | ✅ | +| **每 target / 每目录 C++ 标准** | ✅ | 🚨 **下限 c++23,`-std=` 被硬拦** | 需上游 #1 | +| **只构建一个 target** | ✅ | ❌ 位置参数被忽略 | ninja 兜底 / 上游 #2 | +| **坏兄弟不拖垮好 target** | ✅ | ❌ 单包全挂且零产物 | ninja 兜底 | +| **枚举 target** | ✅ 插件 | ❌ 无命令、无 JSON | 生成器兜底 / 上游 #3 | +| 插件机制(`add_plugindirs`) | ✅ | ❌ 无 | 不需要,适配器可独立 | +| 单练习构建耗时(暖) | 0.61 s | **0.014 s** | 大幅改善 | +| 工具链自管理 | ❌ 依赖 xlings pin(3.0.7 已从 registry 移除) | ✅ 沙箱自带 | 大幅改善 | +| Windows | MinGW,需手写 `-static` | MinGW + MSVC,默认静态 | 改善 | + +--- + +## 4. 横向对照:rustlings 和 cargo 是怎么做的 + +dslings 与 rustlings 是同构问题——~155 个单文件练习、**默认就编译不过**、由 checker CLI 驱动。rustlings 恰好在 2024 年做过一次同方向的架构迁移,其取舍和踩到的坑对我们有直接参考价值。 + +### 4.1 rustlings 的两代架构 + +**v5 及以前:直调 `rustc`,不用 cargo。**(`src/exercise.rs` @ tag `5.6.1`) + +```rust +const RUSTC_EDITION_ARGS: &[&str] = &["--edition", "2021"]; +const CLIPPY_CARGO_TOML_PATH: &str = "./exercises/clippy/Cargo.toml"; + +Mode::Compile => Command::new("rustc") + .args([self.path.to_str().unwrap(), "-o", &temp_file()]) + .args(RUSTC_COLOR_ARGS).args(RUSTC_EDITION_ARGS).output(), +``` + +产物是 CWD 下 pid+线程 id 命名的临时文件,靠 `impl Drop for FileHandle` 回收。IDE 支持靠**另一套**手写生成的 `rust-project.json`(`src/project.rs`,需要手动跑 `rustlings lsp`)。clippy 则再套一层 hack:运行时往固定路径写一个临时 `Cargo.toml`、`cargo clean`、`cargo clippy`——每次全量重建,且练习被编译两遍。 + +**两套真相源直接酿成 bug。** PR #1355 记录得很清楚: + +> The edition args of `rustc` is set to 2018 by default. While rustling generate `rust-project.json` with edition setting to 2021. It may cause some problems. + +**v6(2024-03-31,commit `82b563f1`,`src/exercise.rs +56/−204`):生成 `Cargo.toml`,改用 cargo。** 动机在 issue #1935 里说得很直白,**三条理由里没有一条是速度**: + +> We can generate a `Cargo.toml` file containing a `[[bin]]` entry for every exercise. This should make things much smoother and less hacky, especially because we have many issues related to the **language server**. This should also enable us to use Cargo instead of rustc to run the exercises. That would especially make **Clippy** exercises less of a trouble. This approach also allows us to easily add **dependencies** to the exercises in case we want to do so in the future. + +即:**LSP、Clippy、未来的依赖管理**——外加消灭第二套真相源。 + +### 4.2 v6 的具体机制 + +| 项 | rustlings 做法 | +|---|---| +| 清单 | `dev/Cargo.toml` 是模板,**生成且提交进仓库**(不 gitignore)。只有 `bin = [...]` 那一段被机器重写(`src/cargo_toml.rs::bins_start_end_ind` 按字节偏移做字符串手术),其余手写内容原样保留,学习者可自行加 `[dependencies]` | +| 何时重新生成 | 只在显式 `rustlings dev update`,**从不在运行时隐式生成**。CI 用 `dev check` 重新生成并逐字节比对,不一致就报 "Cargo.toml is outdated" | +| 条目形式 | 不是 `[[bin]]` 段头,是等价的内联表数组,**只有 `name` 和 `path` 两个键**:`{ name = "intro1", path = "../exercises/00_intro/intro1.rs" }`。必须放在任何 table 头之前 | +| 规模 | 94 个练习 → **188 个 bin**(每个练习额外生成一个 `_sol` 指向参考答案) | +| 构建命令 | `cargo build -q --bin ` → 失败即止;`cargo test -q --bin `;`cargo clippy -q --bin --profile test`;最后**直接 exec `target/debug/`,不用 `cargo run`** | +| 诊断格式 | **纯文本**,不用 `--message-format=json`。`cargo metadata` 只用来取 `target_directory` | +| 练习清单来源 | `rustlings-macros/info.toml`,proc macro 在编译期 `include_bytes!` 进二进制。字段:`name` / `dir` / `test`(默认真) / `strict_clippy` / `hint` / `skip_check_unsolved` | +| 通过判定 | **纯退出码**,无输出匹配。特别地,为了避免练习里裸 `exit(1)` 让人一头雾水,会补一句 "The exercise didn't run successfully (nonzero exit code)" | +| 完成状态 | `.rustlings-state.txt`(gitignore)。格式极简:第 3 行是当前练习名,第 5 行起是已完成练习名。**只缓存"在哪一题"和"哪些做完了"**,不缓存编译输出。用名字不用索引,所以重排 `info.toml` 不会毁进度 | +| 文件监听 | `notify` v8 + **200ms 去抖**(脏位图,N 次快速保存塌缩成 1 次重建)+ `EXERCISE_RUNNING: AtomicBool` 自触发保护 + 激进事件过滤(只放行 `Modify::*` 和 `Access::Close(Write)`) | + +`// I AM NOT DONE` 标记**在 v6 已被删除**,改为按 `n` 显式进入下一题 + 持久化状态。 + +### 4.3 cargo 的能力(我在本机 cargo 1.89 实测) + +做了和 mcpp 完全对等的实验(3 个 bin,`ex-b` 故意写坏): + +| 能力 | 结果 | +|---|---| +| `cargo build --bin ex-a` | ✅ exit 0,只产出 `ex-a`,坏兄弟完全无关 | +| `cargo build --bin ex-b` | ✅ exit 101 | +| `cargo run --bin ex-a` | ✅ 且**透传程序退出码**(实测 `exit(3)` → 101 之外的 3) | +| `cargo metadata --format-version 1 --no-deps` | ✅ JSON 含 name + **绝对 `src_path`** + edition;**练习编译不过时照样 exit 0**(清单层查询,不编译) | +| workspace `members = ["ex/*"]` glob | ✅ 可用(mcpp 文档写了但实测报错) | +| `--message-format=json` | ✅ 给出 `file:line:col` 结构化诊断 | +| 逐 bin 构建耗时 | 暖 0.055s / 改动后 0.136s / `metadata` 0.038s | + +**🚨 但 per-`[[bin]]` `edition` 是个陷阱。** 它确实能工作(实测包级 2021 + 单 bin 覆盖 2015,2015-only 代码正确通过/拒绝),**但 cargo 会警告并正在移除**: + +``` +warning: `edition` is set on binary `ex-c` which is deprecated +``` + +cargo book 标注该字段 *"deprecated and will be removed in a future Edition"*。而 rustlings **从未使用过它**——全仓库 grep `edition` 只有一个值 `2024`,且从不出现在 bin 条目里;`append_bins()` 在代码层面就只能写 `name` 和 `path`;`ExerciseInfo` 没有任何 edition/flags 字段。188 个 target 全部继承唯一的包级 `edition = "2024"`。 + +> 而且即便只有一个包级 edition,rustlings 也已经踩到漂移风险——`Cargo.toml:17` 挂着注释 `# On Update: Update the edition of rustfmt in dev check and CARGO_TOML in dev new`,同一个值手工同步三处。 + +**结论:语言版本的正确粒度是「包」,不是「target」。** 这直接否定了我原先"给 mcpp 加 `[targets.X].standard`"的想法。 + +### 4.4 修订后的推荐架构:按标准分 workspace member + +既然粒度是包,而 **d2mcpp 的目录结构本来就是按标准组织的**,两者天然对齐: + +``` +mcpp.toml [workspace] members = ["dslings/cpp11", "dslings/cpp14", ...] +dslings/cpp11/mcpp.toml standard = "c++11" + 49 个 [targets.*] +dslings/cpp14/mcpp.toml standard = "c++14" + 2 个 +dslings/cpp17/mcpp.toml standard = "c++17" +dslings/cpp20/mcpp.toml standard = "c++20" +dslings/cpp23/mcpp.toml standard = "c++23" +``` + +**5~10 个 member,不是 155 个。** §2.4 里反对 workspace 的四条理由全部失效:members 不用 glob(10 条字面路径无所谓)、10 个 `mcpp.toml` 不是负担、`include_dirs` 重复 10 次不是负担、串行构建 10 个 member 也不是负担。 + +已实测验证(用 c++23/c++26 两个 member,因为 c++11 目前仍被拒): + +``` +cpp23 member -> ['-std=c++23'] ← 各自 compile_commands.json +cpp26 member -> ['-std=c++26'] +``` +**每 member 的 `standard` 正确落到编译行。** 且 `mcpp build -p cpp26` 在 `cpp23` member 有坏练习时正常返回 0。 + +剩余问题只有两个,都已有解: +- **member 内部**仍需逐 target 隔离(一个坏练习会拖垮同 member 的 49 个)→ ninja 兜底(§2.3 已实测)或上游需求 2。 +- `08-literal-type-0` 需要 c++17 但住在 cpp11 目录 → 单独开一个小 member,或挪到 cpp17。 + +**上游需求从 3 个降为 1 个必需:只剩 `[package].standard` 放宽。** 而且这个方向与 cargo 的包粒度哲学一致,不是在跟工具较劲。 + +### 4.5 rustlings 踩过的坑:哪些我们会中、哪些不会 + +**⚠️ 会中的:性能是这个模型引入的**回归**,不是收益。** issue #2071「Checking an exercise takes too long」(2024-08 提出,**至今未关**): + +> every time I update the code of an exercise, the `rust-analyzer` builds the whole `exercises` folder (it has like 156 exercises...). During this process, I cannot use any command. + +维护者承认 checker 和 IDE 争抢同一个 cargo lock 与 target 目录,且保存一次就全量失效重算。连带 #2113「Rustling is slow」、#2091「Too many open files (os error 24)」、#2072「LSP issues because of too many errors」。至今只有缓解措施(`rust-analyzer.cargo.targetDir` 隔离目录)。 + +**✅ 但我们大概率不会中最严重的那条**——因为这本质是 **rust-analyzer 特有的全 crate 检查模型**。C++ 侧是 clangd + `compile_commands.json`,**逐 TU 按需**,第 90 个练习编译不过不影响第 3 个的诊断。我实测确认 mcpp 的行为正好支持这点: + +- **构建失败时 `compile_commands.json` 照样生成**(104-target spike:`mcpp build` 退出 1,但 104 条 entry 齐全) +- 每条 entry 带自己的 `-std=`,配合 §4.4 的分 member 架构,clangd 能对每个练习显示**正确标准**下的诊断 + +**这反而是迁移的一个净收益。** d2mcpp 现在**没有** `compile_commands.json`(`.gitignore:49` 预留了位置但文件不存在),IDE 靠 `.vscode/settings.json` 里手写的 `C_Cpp.default.includePath`——它不编码任何 `-std=`,等于**全仓库一个标准**。这正是 rustlings PR #1355 那类"两套真相源"bug 的同款形态。 + +**✅ 独立于构建系统的、更便宜的一个win:done-state 缓存。** rustlings 的"每次重编所有练习"抱怨(#121/#132/#1843)**早于 v6,且是靠 `.rustlings-state.txt` 解决的,不是靠换 cargo**。d2x 目前没有任何完成状态持久化。这件事现在就能做,与 xmake/mcpp 之争无关。 + +**✅ 值得直接抄的 CI 门禁。** rustlings 的 `cargo dev check --require-solutions` 断言:**每个练习都必须失败,每个参考答案都必须通过**。对照 §3.4 第 1 条——d2mcpp 的 `dslings-ref-ci.yml` 目前是静默空转,参考答案零校验。这个门禁应该优先补上。 + +**✅ 值得抄的两个防御细节:** +- rustlings 全量检查时,**"报错"(而非"失败")的练习会退回串行重试**,注释写明 *"it could be because we exceeded the limit of open file descriptors"*。155 个 target 并发时同样会遇到。 +- 文件监听必须有**自触发保护**(构建自身的写入不能反过来触发重建)+ **去抖**。d2x 现在是 `wait_files_changed` 轮询 mtime,没有这两层。 + +### 4.6 一句话总结 + +rustlings 的证据**支持**"生成单一构建描述、一个练习一个 target"这条路线,但**理由是 IDE/lint 集成和消灭第二套真相源,不是速度**。语言版本用**包**粒度(cargo 正在废弃 target 粒度),这恰好让 d2mcpp 的"按标准分目录"结构变成天然的 workspace member 划分,把 mcpp 的上游需求压缩到只剩一条。 diff --git a/.agents/docs/2026-07-20-mcpp-provider-reference.md b/.agents/docs/2026-07-20-mcpp-provider-reference.md new file mode 100644 index 0000000..fcb8cb4 --- /dev/null +++ b/.agents/docs/2026-07-20-mcpp-provider-reference.md @@ -0,0 +1,264 @@ +# d2mcpp Provider 与练习脚手架 参考 + +- 日期:2026-07-20 +- 分支:`feat/mcpp-provider` +- 配套调研:[`2026-07-19-mcpp-replace-xmake-research.md`](2026-07-19-mcpp-replace-xmake-research.md)(xmake → mcpp 的可行性论证与 rustlings/cargo 横向对照) +- d2x 侧协议规范:d2x 仓库 `.agents/docs/2026-07-20-d2x-architecture-reference.md` +- 本文定位:**当前实现的参考手册**——目录约定、生成物、判定机制、维护须知 + + +> **⚠️ 2026-07-23 起本文的 §4(清单生成)与 §5(判定机制)已被「练习即测试」迁移取代,现状见 [`2026-07-23-exercises-as-tests-reference.md`](2026-07-23-exercises-as-tests-reference.md)。** +--- + +## 1. 全景 + +xmake 已完全退役。构建链路是: + +``` +d2x(通用框架,零内置后端) + └─ Provider Protocol (NDJSON) ─→ d2x/buildtools/mcpp/ ← 本仓库自己的 Provider(C++26) + ├─ 目录约定发现练习 + ├─ 生成 mcpp workspace 清单 + ├─ 调 mcpp build/run + └─ 读侧信道判定通过 + ↓ + mcpp(未做任何改动) +``` + +### 提交进仓库的包 + +``` +mcpp.toml [workspace] members = ["d2x/buildtools/mcpp", "dslings/harness"] +d2x/buildtools/mcpp/ Provider,standard = "c++26" +dslings/harness/ 练习脚手架库,standard = "c++23" +``` + +### 生成物(gitignore) + +``` +.d2x/build/mcpp.toml 独立 workspace 根 +.d2x/build//mcpp.toml 该标准下全部 target —— 供 clangd +.d2x/build/_current/mcpp.toml 只含当前一题 —— 供 checker +.d2x/build/_current/result.ndjson 判定用侧信道 +.d2x/state.json 学习者进度(d2x 写) +``` + +--- + +## 2. 引导:零脚本、Windows 安全 + +`.d2x.json`: + +```json +{ "buildtools": "mcpp run -q -p d2x/buildtools/mcpp --" } +``` + +d2x 拼接后得到 `mcpp run -q -p d2x/buildtools/mcpp -- check `。**从仓库根执行、无需 cd、首次自动构建 Provider**,暖开销约 26ms。 + +d2x 从不 `chdir`(它在静态初始化时捕获 CWD),所以免 `cd` 是硬要求。注意 `mcpp` 的 `-p` 匹配的是**目录 basename 或完整相对路径**,不是包名。 + +### ⚠️ 嵌套 mcpp 与 `LD_LIBRARY_PATH` + +`mcpp run` 会把 `LD_LIBRARY_PATH` 指向它私有的 glibc 并注入子进程。Provider 再去 spawn 嵌套的 `mcpp` 时被迫加载错配的 glibc,**在动态链接器里段错误**(冷启动稳定复现,输出只剩 `:\t__vdso_time` 这样的 trace 残片)。 + +`runner.cppm` 在每次 spawn 前 `unsetenv("LD_LIBRARY_PATH")` 绕过;mcpp 会为它自己的子进程重新设置正确的值。 + +d2x 侧对同一问题早有相同处理(`platform.cppm`),仓库里还留着 `workaround_ld_library_path_issue` 分支——**这是 mcpp 的既有问题,值得单独向上游报**。 + +--- + +## 3. 练习发现:目录约定 + 就近指令 + +**没有声明文件。** 放一个 `.cpp` 进去就是全部工作。 + +rustlings 最贵的一课是 PR #1355:Rust edition 同时写在 `rustc` 参数和 `rust-project.json` 里,两边漂移酿成 bug。**任何独立声明文件都是第二套真相源。** 这里的真相只有两处,且都无法漂移:目录结构,和练习文件自己的头部注释。 + +### 目录布局 + +``` +dslings/hello-mcpp.cpp 入门练习(chapter = intro) +dslings//NN-topic-K.cpp zh 练习 +dslings/en//NN-topic-K.cpp en 练习(lang=en 时启用,与 zh 互斥) +solutions//NN-topic-K.cpp 参考答案(zh/en 共用同一份) +``` + +### id / order / chapter 的推导 + +| 文件 | id | chapter | order | +|---|---|---|---| +| `dslings/cpp11/00-auto-and-decltype-0.cpp` | `cpp11-00-auto-and-decltype-0` | `cpp11/00-auto-and-decltype` | 1100000 | +| `dslings/cpp11/03-trailing-return-type.cpp` | `cpp11-03-trailing-return-type` | `cpp11/03-trailing-return-type` | 1100300 | +| `dslings/hello-mcpp.cpp` | `hello-mcpp` | `intro` | -100000 | + +`order = std_rank × 100000 + 章节号 × 100 + 练习序号`。尾部 `-<数字>` 是序号,没有就当 0(仓库里 03/04 两章确实缺 `-0` 后缀,规则把它们归一化)。 + +### 每练习编译选项 + +写在练习文件自己的头部注释里(只扫前 40 行): + +```cpp +// d2x:cxxflags: -O0 -fno-elide-constructors +``` + +仓库现存用例:`04-rvalue-references`(观察移动)、`07-constexpr-0`(`-Wpedantic -Werror` 让 VLA 成为错误)。 + +### id 白名单 + +id 只允许 `[A-Za-z0-9._-]`,违反者**被拒绝并打印到 stderr**,不进入枚举。 + +因为 id 有两个危险去向:d2x 拼进 shell 命令、我们写进生成的 TOML(`[targets.]`)。在源头挡住比在两个下游各自转义更可靠——这类文件名本就是笔误或恶意 PR,与其想办法安全传递,不如让作者改名。 + +--- + +## 4. 双 member 布局 + +**硬约束:dslings 的练习默认就编译不过**(49 个带 `D2X_YOUR_ANSWER`),而 mcpp 的 `build` 和 `run` 都会先全量构建整个包——一个坏兄弟拖垮全部且零产物。实测: + +``` +member 含全部 3 题(后两题未做完)→ mcpp build -p → exit=1 ← 当前这题被拖挂 +只生成当前这一题 → 0.071s,exit=0 +``` + +**member 粒度(标准/特性/练习)本身不解决逐题隔离。** 所以分两个: + +| 目录 | 内容 | 用途 | +|---|---|---| +| `.d2x/build//` | 该标准下全部 target | clangd —— 即使多数练习编译不过,mcpp 仍生成完整 `compile_commands.json`,IDE 对每题都有正确编译参数 | +| `.d2x/build/_current/` | 只含要验证的那一题 | checker | + +实测动态改写清单代价极低:切题 0.118s、切回 0.018s,**fingerprint 目录始终只有 1 个**(改写 target 集合不会让缓存爆炸)。 + +### 其他生成细节 + +- `main` 用 `../../../` 逃逸出包根,**练习源文件原地不动** +- 脚手架走 `[dependencies] path` 依赖,而非把仓库根塞进 include 搜索路径(后者会让练习能 `#include` 仓库里任何文件) +- `-fmacro-prefix-map=/=` 让 `__FILE__` 相对仓库根,学习者看到的报错不再顶着一长串 `/home/...` +- 所有清单**内容比对后才落盘**,不推进 mtime,保住 mcpp 的快速路径 +- `check` 会先 `write_full` 再 `write_current`——全新仓库上学习者直接跑 `d2x checker` 时根清单还不存在,否则 mcpp 报退出码 2 + +--- + +## 5. 判定机制 + +### 侧信道,不是扫 stdout + +判定原先 100% 是带内信号:断言失败**并不改变退出码**(实测 exit=0),所以只能扫 stdout 找 `❌`。这会误判——一个断言全过的正确解答,只要在说明文字里打了个 `❌` 就被判失败(已复现)。反过来,输出截断或 Windows 控制台代码页不对,判定同样失效。 + +现在 stdout 回归「给人看」,判定走侧信道: + +```jsonc +{"kind":"assert","ok":false,"expr":"a == b","expected":"1","actual":"2", + "file":"dslings/cpp11/xx.cpp","line":33} +{"kind":"wait","file":"dslings/cpp11/xx.cpp","line":40} +``` + +**逐条追加而非退出时统一写** —— 练习段错误时,崩溃之前的断言结果照样保留。 + +`D2X_RESULT_FILE` 环境变量未设置时 harness 只打印不写文件:**学习者直接跑二进制零摩擦**。 + +### 判定顺序 + +| 侧信道内容 | Verdict | +|---|---| +| 有 `ok:false` | `fail` + 每条失败转一个 `Diagnostic` | +| 无失败但退出码非 0 | `fail` | +| 无失败、有 `wait` | `blocked` | +| **文件不存在**(练习没用 harness) | 退回「编译通过 + 退出 0 = `pass`」 | + +最后一条让 **harness 自动变成可选的**,不需要额外机制:纯观察型练习(现有 18 个只用 `D2X_WAIT`)可以写成零依赖的纯 C++ 文件,学习者能原样拷进 Compiler Explorer。 + +### 路径:展示 vs 定位 + +侧信道里的 `file` 因 `-fmacro-prefix-map` 是相对路径(学习者看着舒服),但协议要求绝对路径(d2x 靠它开编辑器、监听变更)。**在协议边界上还原成绝对。** + +--- + +## 6. 练习脚手架 `dslings/harness/` + +按库设计,目前住在本仓库,将来可整体抽成独立 mcpp 包给其他 C++ 课程复用。 + +### 两条路径不等价 + +| 设施 | `#include ` | `import d2x.harness;` | +|---|---|---| +| 断言 | `d2x_assert` / `d2x_assert_eq` 宏 | `d2x::check` / `check_eq`,`source_location` 自动带 file/line | +| 路障 | `D2X_WAIT` | `d2x::wait()` | +| 填空占位 | `D2X_YOUR_ANSWER` | **无等价物** | + +**宏无法跨模块导出**,这是 C++ 的硬约束而非疏漏。`D2X_YOUR_ANSWER` 必须展开为空才能制造编译错误,本质就是宏。**cpp20/cpp23 等模块化章节需要另设填空约定——这是个尚未决策的缺口。** + +`include/` 下保持 `d2x/cpp/common.hpp` 这个既有路径,所以 104 个练习和书本一行都不用改。路径改名可以以后单独做。 + +### 维护须知 + +`d2x_assert_eq` 的**所有分支**都必须走 `d2x::detail::show()`,不能用裸 `std::to_string`——后者没有 `std::string` / `const char*` / scoped enum 的重载,一旦有练习比较这些类型就会硬编译失败。(曾经上报分支用了 `show()` 而日志分支没用,是个潜伏的地雷。) + +--- + +## 7. 测试 + +### `d2x/buildtools/mcpp/tests/e2e.sh` + +断言两件事,缺一不可:**每个练习未完成时不通过**、**每个参考答案放进去后通过**。等价于 rustlings 的 `cargo dev check --require-solutions`。 + +走的是 `d2x checker` 内部同一条 Provider 路径,所以绿灯等价于学习者本地能跑通,而非另一条平行路径。 + +**两道防线:** + +1. **防空转**——`pass == 0` 时直接判失败。旧 CI 就是这么绿了很久的:它只挑 `-ref` 目标,而 `solutions/` 早被注释掉,循环一次都没进,job 照样退出 0;第 60 行的 `wc -l` 对空串还打印 "Found 1 reference targets" 把空转掩盖了。同类问题在本脚本自己身上也犯过一次(`${sol#en/}` 剥离顺序错,导致所有英文答案静默 SKIP)。 + +2. **脏树检查**——练习目录有未提交改动时**拒绝运行**并列出文件。脚本会把参考答案覆盖到练习上再还原,天然会吃掉未提交的改动,这个陷阱咬过两次。 + +### 当前状态 + +| 项 | 结果 | +|---|---| +| Provider 枚举 | 52 题(zh:1 + 49 + 2;en 同样 52) | +| 端到端 zh | 51/51 参考答案通过 | +| 端到端 en | 51/51 参考答案通过 | +| d2x session 单测 | 28/28 | +| 事件流 | 纯 JSON,0 污染 | +| 注入防护 | 恶意文件名被拒绝,命令未执行 | + +--- + +## 8. C++ 标准与教学漂移 + +**所有练习按 `c++23` 编译。** mcpp 目前硬拒 `c++11/14/17/20`(`src/manifest/types.cppm` 的白名单),本方案选择不改 mcpp 上游。因此 `cppNN/` 目录现在表示**特性引入于哪个标准**,不再改变编译参数。 + +### 已知代价 + +`04-rvalue-references` 的移动构造教学点。C++17 起 prvalue 直接初始化目标(保证复制省略),`-fno-elide-constructors` 再也无法让 `Object obj = Object();` 产生移动构造。 + +**修法:** 改成从具名对象 `std::move`(任何标准下都必然调用移动构造),并补一条 `d2x_assert(move_ctor_calls >= 1)`。 + +**更重要的是那条断言。** 漂移之所以能静默发生,正是因为从前没有任何断言检查它——输出少一行没人发现。现在它是 CI 可检测的事实。 + +> **教训:教学点如果没有断言覆盖,它的消失就是不可见的。** 新增练习时应问:这一课的核心观测点,有断言在守着吗? + +量化过的风险面:51 个参考答案在「原标准 vs c++23」下逐一编译并 diff 运行输出,**50 个完全一致,仅此 1 个漂移**。但随着课程往 cpp17/20 扩写,这类静默漂移只会变多。 + +--- + +## 9. 撰稿流程的变化 + +`.agents/skills/d2mcpp-authoring/` 已同步更新: + +- **练习不再需要注册**——放进 `dslings//` 即被目录约定发现 +- 新增 `` 章节只需建目录 + 改两个 `SUMMARY.md`,无构建文件接线 +- 每练习编译选项改为文件头部 `// d2x:cxxflags:` 指令 +- 验证命令改为 `mcpp run -q -p d2x/buildtools/mcpp -- check ` 或整体 `bash d2x/buildtools/mcpp/tests/e2e.sh` + +--- + +## 10. 已知缺口 + +| 缺口 | 影响 | +|---|---| +| **模块化练习的填空占位符无约定** | `D2X_YOUR_ANSWER` 是宏,跨不了模块边界;cpp20/cpp23 章节需先决策 | +| **macOS / Windows 从未验证** | `_popen`、`_putenv_s` 的 `#ifdef` 分支全是纸面推断 | +| **新 CI 从未真跑过** | workflow 是手写的,`xlings install -y` 在 CI 环境能否装上 mcpp 未验证 | +| **`diagnostics` 只覆盖运行期断言** | 编译错误尚未解析成结构化诊断 | +| **Provider 侧无单测** | discovery 的 id/order/chapter 推导、manifest 生成都只被端到端间接覆盖 | +| **`hello-mcpp` 无参考答案** | e2e 只能 SKIP 它,入门练习实际未被验证 | +| **`solutions/` 无 en 镜像** | 设计如此(共用一份),但意味着 en 专有的措辞错误无法被答案校验发现 | diff --git a/.agents/docs/2026-07-23-exercises-as-tests-design.md b/.agents/docs/2026-07-23-exercises-as-tests-design.md new file mode 100644 index 0000000..0953517 --- /dev/null +++ b/.agents/docs/2026-07-23-exercises-as-tests-design.md @@ -0,0 +1,260 @@ +# 练习即测试:d2mcpp 架构重设计(设计稿) + +- 日期:2026-07-23 +- 状态:**设计已讨论定稿,未实现** +- 前置阅读: + - [`2026-07-20-mcpp-provider-reference.md`](2026-07-20-mcpp-provider-reference.md)(当前实现,本设计将取代其中的清单生成与判定部分) + - d2x 仓库 `.agents/docs/2026-07-20-d2x-architecture-reference.md`(Provider 协议,本设计不改协议) +- 本文定位:第二轮重设计的**决策记录与实施蓝图**——双入口定位、练习即 tests/、无宏 harness、mcpp 上游改动清单 + +--- + +## 1. 目标与定位 + +### 双入口 + +| 入口 | 体验 | 谁负责 | +|---|---|---| +| `d2x checker` | **闯关游戏**:顺序推进、进度持久化、将来的随机抽题/错题重练/游戏化呈现 | d2x | +| `mcpp test` / `mcpp run` | **真实工程**:cd 进标准目录直接用 mcpp,进度表就是测试结果,零生成物零魔法 | d2mcpp + mcpp | + +两条入口驱动**同一份练习、同一条判定链路**,不存在平行路径。 + +### 责任划分(重申并收紧) + +- **d2x**:拥有学习循环和它的呈现。判定信号拿去做进度显示还是做成游戏,d2mcpp 不关心也感知不到。将来的「随机出题」等策略是 d2x 会话层的事——协议本就是 `check ` 按需判定,**协议与 d2mcpp 均无需改动**。若将来需要「同一题随机参数」,协议预留 `check --seed N` 扩展位,现在不做。 +- **d2mcpp**:提供关卡(练习内容)+ 判定事实(编译过没过、断言挂没挂、路障拆没拆)。与 mcpp 和模块化深度绑定:harness 是纯 C++ 模块,判定复用 `mcpp test`。 +- **mcpp**:通用构建/测试工具。本设计需要它补三个**通用**能力(§4),均为 cargo/ctest 已验证的形态,不含任何 d2x 定制逻辑。 + +### 教学标准约定(维持既有决策) + +所有练习统一按 **c++23** 编译;`cppNN/` 表示**特性引入于哪个标准**,内容只用该标准的特性,不改变编译参数。教学点必须有断言守着(防静默漂移,见 provider-reference §8)。 + +--- + +## 2. 方案对比与结论 + +| 方案 | 形态 | 结论 | +|---|---|---| +| **A. 标准即工程,练习即 tests/** | `cpp11/` 是真实 mcpp 工程,练习是 `tests/<章节>/<序号>.cpp` | **采纳** | +| B. 章节即工程 | 每章一个 mcpp 工程,workspace 挂 30+ member | 否。频繁 cd + 30 多个 mcpp.toml 纯属维护负担;「章节」用 tests/ 子目录即可表达;仅当章节需要各自不同依赖时才值这个价(现状 52 题里为零) | +| C. 不改上游(现状延续) | Provider 继续生成 `_current` 清单 | 否。原生体验只能到「mcpp run 单题」,拿不到「mcpp test = 进度表」这个最贴合闯关直觉的形态 | + +方案 A 的前提是 mcpp 上游三改动(§4)。实验已证实当前行为不可用:**一个编译不过的测试 → 整体 `error: build failed`,零测试执行**(实测 mcpp v0.0.99,三个测试一好一运行错一编译错)。而「填空未填 = 编译不过」是练习的常态。 + +--- + +## 3. 目录布局 + +``` +d2mcpp/ + mcpp.toml workspace members = [harness, cpp11, cpp14, ...] + harness/ 独立 mcpp 包(standard c++23,纯模块,无宏) + cpp11/ + mcpp.toml 真实工程:standard = "c++23",[dependencies] harness (path) + tests/ + 00-auto-and-decltype/0.cpp + 00-auto-and-decltype/1.cpp + 01-nullptr/0.cpp + ... + cpp14/ ...同构 + solutions/ + cpp11/00-auto-and-decltype/0.cpp 结构镜像 tests/(zh/en 共用一份,维持现状) +``` + +- 章节 = tests/ 下的子目录(`mcpp test` 本就递归收集 `tests/**/*.cpp`)。 +- id 推导沿用目录约定:`cpp11/tests/00-auto-and-decltype/0.cpp` → `cpp11-00-auto-and-decltype-0`,order 公式不变(std_rank × 100000 + 章节 × 100 + 序号)。id 白名单 `[A-Za-z0-9._-]` 在源头拒绝,理由不变(注入纵深防御)。 +- `dslings/` 目录退役;`hello-mcpp` 入门练习移入独立的 `intro/` 工程(同构,一个测试),并补参考答案(闭掉「e2e 只能 SKIP 它」的缺口)。 +- **`.d2x/build/` 不复存在**:无生成清单、无 `_current` 改写。`.d2x/state.json`(d2x 写)保留。 +- clangd:由 mcpp 为 tests/ 生成的 `compile_commands.json` 覆盖(实施时验证:练习编译不过时条目是否仍生成——若否,此项是上游第四个小改动)。 + +### en 练习 + +维持「zh/en 互斥启用」语义。en 练习放 `cpp11/tests-en/` 还是独立 `cpp11-en/` 工程,实施时按 mcpp 对非常规测试目录的支持度定(倾向前者 + mcpp.toml 可配 tests 路径;这也是通用能力)。**本条是实施期待定项,不影响架构。** + +--- + +## 4. mcpp 上游改动清单 + +三个改动,全部是通用能力,d2mcpp 只是第一个消费者。 + +### 4.1 逐测试编译隔离 + +`tests/` 下每个 `.cpp` 本来就是独立二进制 target。改动后:单个测试编译失败 → **该测试**标记 fail(reason = compile),其余照常编译运行;整体退出码非 0 但不再是「build failed 零执行」。ctest/meson 的既有行为;「写坏一个测试导致其他测试全跑不了」对任何 mcpp 用户都是缺陷。 + +**验收**:一好一运行错一编译错的三测试工程,`mcpp test` 三个都有结果,好的那个真的执行了。 + +### 4.2 测试过滤 + +`mcpp test `,按测试名(tests/ 下相对路径去扩展名)子串或 glob 过滤。对齐 `cargo test `。 + +**验收**:`mcpp test 00-auto` 只编译运行匹配的测试;Provider 的 `check ` 走 `mcpp test --filter <精确名>`。 + +### 4.3 机器可读结果 `--message-format json` + +每测试一行 NDJSON: + +```jsonc +{"test":"00-auto-and-decltype/0", + "status":"pass|compile_fail|run_fail", + "exit_code":0, "signal":null, + "compile_output":"...编译器原文...", + "run_output":"...合并的 stdout+stderr..."} +``` + +**必须区分错误层级**:包级构建失败(harness 或 lib target 挂了)≠ 测试级编译失败。包级失败单独一条 `{"error":"package", ...}`,否则 52 题全标红会把「课程基础设施坏了」误报成「你全做错了」(对应 d2x 侧「describe 失败 = Provider 挂了,而非没有练习」原则)。 + +对齐 `cargo --message-format=json`;任何 CI/IDE 集成都需要。 + +### 顺带修复 + +嵌套 mcpp 的 `LD_LIBRARY_PATH` 段错误在上游正式修掉(mcpp spawn 子进程时不让私有 glibc 路径泄漏给非 mcpp 二进制),随后删除 d2mcpp `runner.cppm` 与 d2x `platform.cppm` 两处 `unsetenv` workaround。 + +### 待验证的第四项(小) + +练习编译不过时 `compile_commands.json` 是否仍含该条目(clangd 依赖);若否,补之。 + +--- + +## 5. 判定链路 + +``` +harness(运行期事实) → mcpp test(编译/退出码事实) → Provider(合并成 verdict) → d2x(呈现,d2mcpp 不关心) +``` + +### 三个核心要素的唯一事实来源 + +| 要素 | 来源 | 说明 | +|---|---|---| +| 当前判定的练习文件 | **Provider 的目录约定**(不经过 mcpp) | 发现阶段建立 id ↔ 绝对路径映射;mcpp JSON 里的测试名仅用于对账 | +| 编译期错误 | mcpp JSON(`status:compile_fail` + `compile_output` 原文) | 原文转协议 `output` 事件;`unknown type name 'D2X_YOUR_ANSWER'` 指着要填的行,是教学主通道 | +| 运行期错误 | mcpp JSON(退出码/信号)× 侧信道(断言详情/wait) | 侧信道逐条追加写,崩溃前的记录保得住 | + +### 判定顺序(Provider 内,语义与旧 `judge_run` 一致) + +| 观察 | Verdict | +|---|---| +| mcpp 报 `compile_fail` | `fail` + 编译输出 | +| 侧信道有 `ok:false` | `fail` + 每条失败转一个 Diagnostic | +| 无断言失败但退出码非 0(纯崩溃) | `fail` + 运行输出 | +| 无失败、有 `wait` | `blocked` | +| 侧信道文件不存在(未用 harness 的纯观察题) | 退回「退出码 0 = pass」 | + +结构化的**编译期** diagnostics(file/line 进协议字段)仍是既有缺口,本设计不倒退也不顺带解决;将来经 `-fdiagnostics-format=json` 做独立增量。 + +--- + +## 6. 无宏 harness + +### 关键事实:填空占位符不需要是宏 + +实验对比(clang 21,c++23): + +| 方案 | 报错 | +|---|---| +| 宏展开为空(现状) | `use of undeclared identifier 'b1'` ——指着错误位置、级联报两次 | +| **裸标识符(新)** | `unknown type name 'D2X_YOUR_ANSWER'` ——正好指着要填的地方,只报一次 | + +所以 `D2X_YOUR_ANSWER` 保留拼写但**降格为纯约定**:不定义在任何地方、不需要任何头文件、在模块化练习里天然可用、拷进 Compiler Explorer 也成立。旧文档「宏跨不了模块边界,模块化章节填空无约定」这个缺口是**伪问题,就此关闭**。 + +### harness 包接口(`import d2x.harness;`) + +```cpp +export namespace d2x { + // 断言:source_location 自动带 file/line;同时打印人读输出(✅/❌ 逐条对照,教学的一部分) + // 并在 D2X_RESULT_FILE 设置时逐条追加写侧信道 + bool check(bool ok, std::string_view what = {}, + std::source_location loc = std::source_location::current()); + template + bool check_eq(const A& a, const B& b, std::string_view what = {}, + std::source_location loc = std::source_location::current()); + + // 路障:打印「读完后删掉这一行」提示并记入侧信道 + void wait(std::source_location loc = std::source_location::current()); +} +``` + +- **退出码机制**:首次调用任一 API 时注册 `atexit` 处理器;进程正常退出时若有失败断言或未拆的 wait → `_Exit(1)`。这让裸 `mcpp test` 不需要懂任何 d2x 概念就能显示对错——练习的 `main` 不需要 `return d2x::result()` 这类样板。 +- **`#expr` 字符串化的损失与补偿**:函数版拿不到表达式原文(c++23 无反射)。补偿:`what` 可选参数供作者写语义标签(`check_eq(a1, a2, "auto 与 decltype 推导应一致")`——教学价值高于表达式原文);不传时人读输出退化为值对照 + file:line,学习者看得到出错行。将来 c++26 反射可无侵入恢复原文。 +- 旧的 `d2x/cpp/common.hpp` 经典 include 路径、`honly_logger.hpp`、`D2X_YOUR_ANSWER`/`d2x_assert*`/`D2X_WAIT` 宏全部退役。纯观察型练习依旧可以零依赖(不 import 任何东西)。 +- harness 作为独立 mcpp 包按公共契约维护(本次重设计即冻结接口的时机),将来发 registry 供其他 C++ 课程复用。 + +### 侧信道 schema v2 + +harness 与 Provider 之间的契约,本次显性化 + 加版本: + +```jsonc +{"v":2,"kind":"assert","ok":false,"what":"...","expected":"1","actual":"2", + "file":"cpp11/tests/00-auto-and-decltype/0.cpp","line":38} +{"v":2,"kind":"wait","file":"...","line":45} +``` + +- `D2X_RESULT_FILE` 未设置时只打印不写文件(学习者直接跑二进制零摩擦),语义不变。 +- 逐条追加而非退出时统一写(段错误保留崩溃前记录),语义不变。 +- 写端负责完整 JSON 转义(`"` `\` 控制字符);读端(Provider)字段固定、无嵌套,仍可免 JSON 库。 +- `file` 按编译器给的路径记录,**Provider 在协议边界统一还原为绝对路径**(d2x 靠它开编辑器/监听)。`-fmacro-prefix-map` 不再需要——source_location 在真实工程目录下编译,路径本来就正常。 + +--- + +## 7. Provider 瘦身 + +| 现状 | 新形态 | +|---|---| +| 生成 `.d2x/build/` 三套清单 + `_current` 改写舞蹈 | **全部删除** | +| 自己 popen `mcpp build/run` 并解析 wait status | `mcpp test --filter --message-format json` 一次调用 | +| 判定 = 自己读侧信道 + 自己算退出码 | 判定 = 合并 mcpp JSON × 侧信道(§5 顺序表) | +| 发现 = 扫 `dslings/` | 发现 = 扫 `cpp*/tests/`(约定同构,公式不变) | + +保留:id 白名单、`describe/exercises/check` 三动词、协议事件格式(对 d2x **完全透明**,d2x 零改动)。 + +### 每练习编译选项 + +文件头 `// d2x:cxxflags:` 指令在 tests/ 模式下无法由 Provider 注入(编译由 mcpp 统一驱动)。两个候选:mcpp.toml 支持 per-test 覆盖(通用能力,meson 有先例),或 mcpp 认文件头指令(特化,倾向否)。现存仅 2 题需要(`04-rvalue-references`、`07-constexpr-0`)。**实施期决策项**;若 mcpp.toml 方案成立则指令退役。 + +--- + +## 8. e2e 验证新形态 + +不变的两条硬断言:**每题未完成时不通过、每份参考答案放进去后通过**。 + +- 实现简化:dirty-tree 防护 → 逐题「拷 solution 覆盖 → `mcpp test --filter ` → 还原」,或整体「全部覆盖 → `mcpp test`(此时应全绿)→ 还原」。后者一次构建验全部,优先。 +- 防空转(`pass == 0` 直接失败)与脏树检查两道防线**原样保留**(各自都咬过人,见 provider-reference §7)。 +- `intro/hello-mcpp` 补参考答案后进入 e2e,不再 SKIP。 + +--- + +## 9. 迁移影响面 + +| 项 | 工作量性质 | +|---|---| +| 52 题从 `dslings/` 迁到 `cpp*/tests/` + 宏改函数(`d2x_assert_eq(a,b)` → `d2x::check_eq(a,b)`、`D2X_WAIT` → `d2x::wait();`、`#include ` → `import d2x.harness;`) | 机械,可脚本化 + 人工过一遍 what 标签 | +| 书本(book/)里引用练习路径/代码片段 | 跟随更新,路径变更是主要部分 | +| solutions/ 同步迁移 | 机械 | +| `.agents/skills/d2mcpp-authoring/` 撰稿流程 | 重写「新增练习」章节:放文件进 `cpp*/tests/<章节>/` 即完成注册(约定不变),验证命令改为 `mcpp test ` | +| CI workflow | e2e 命令更新;mcpp 版本 pin 到含三改动的版本 | +| d2x 仓库 | **零改动**(协议不动);仅 smoke CI 的 d2mcpp 分支引用需协调 | + +### 实施顺序(跨仓库依赖) + +``` +mcpp 上游三改动(4.1→4.3,可并行)+ LD_LIBRARY_PATH 修复 → 发版 + → d2mcpp:harness 重写 → 目录迁移 → Provider 瘦身 → e2e/CI → 文档与撰稿技能 + → 与 d2x #31 / d2mcpp #84 的合并顺序问题一并协调(互相咬合,需同步合并 + d2x 发新版) +``` + +本设计建立在 #31/#84 两个 draft PR 之上(协议、三态、侧信道思想全部沿用),是它们的演进而非推翻。 + +--- + +## 10. 本设计关闭/遗留的缺口 + +| provider-reference §10 的缺口 | 状态 | +|---|---| +| 模块化练习填空占位符无约定 | **关闭**(伪问题:裸标识符即编译错误,且报错更好) | +| `hello-mcpp` 无参考答案 | **关闭**(迁入 intro/ 时补) | +| 新 CI 从未真跑过 | 已在 PR #84 上跑绿(2026-07-19),本设计后需再验 | +| macOS / Windows 从未验证 | 遗留;Provider 瘦身后 `_popen`/`_putenv_s` 面积大幅缩小,风险随之降低 | +| 编译错误未结构化 | 遗留;独立增量(`-fdiagnostics-format=json`) | +| Provider 无超时 | 遗留(d2x 侧缺口) | +| en 练习的目录形态 | 新增待定项(§3) | +| per-test 编译选项的 mcpp 承载方式 | 新增待定项(§7) | diff --git a/.agents/docs/2026-07-23-exercises-as-tests-reference.md b/.agents/docs/2026-07-23-exercises-as-tests-reference.md new file mode 100644 index 0000000..9719576 --- /dev/null +++ b/.agents/docs/2026-07-23-exercises-as-tests-reference.md @@ -0,0 +1,92 @@ +# 练习即测试 —— 迁移后参考 + +- 日期:2026-07-23 +- 分支:`feat/mcpp-provider` +- 设计稿:[`2026-07-23-exercises-as-tests-design.md`](2026-07-23-exercises-as-tests-design.md) +- 取代:[`2026-07-20-mcpp-provider-reference.md`](2026-07-20-mcpp-provider-reference.md) 中的清单生成(§4)与判定机制(§5)章节 +- 本文定位:**迁移完成后的现状参考** —— 布局、判定链路、验证结果、依赖版本 + +--- + +## 1. 布局(第二轮重排后:库入驻 d2x/、课程收进 src/) + +``` +mcpp.toml workspace = [d2x, src/*, src/en/*, d2x/buildtools] +d2x/ d2x 练习库(纯模块 `import d2x;`,零宏) +d2x/buildtools/ Provider(C++26) +src/intro/tests/hello-mcpp.cpp +src/cpp11/tests//.cpp 49 题 +src/cpp14/tests/00-generic-lambdas/{0,1}.cpp +src/en/{intro,cpp11,cpp14}/ en 镜像工程(lang=en 时启用,与 zh 互斥) +solutions///.cpp 52 份(zh/en 共用,含 hello-mcpp) +``` + +- **零生成物**:`.d2x/build/` 及三套清单生成已删除;`.d2x/` 下只剩学习进度 + `state.json`(d2x 写)与判定侧信道 `result.ndjson`(harness 写)。 +- id 推导与旧布局**逐字节一致**(`cpp11-00-auto-and-decltype-0`),学习者进度不丢。 + +## 2. 双入口 + +``` +mcpp test -p src/cpp11 原生:进度表(-p cpp11 的 basename 简写同样可用) +mcpp test -p src/cpp11 00-auto 原生:按子串过滤(匹配整章;更长的名字如 + 00-auto-and-decltype/3 即单题) +d2x checker 闯关:文件监听、通过自动推进(已实测:改对 + hello-mcpp 后自动进入 cpp11-00-auto-and-decltype-0) +``` + +同一条链路:`d2x checker → Provider → mcpp test --message-format json → 判定`; +Provider 只是把 mcpp 的 JSON 记录 × 侧信道合并成协议 verdict。 + +## 3. d2x 库(`import d2x;`,包与模块同名,住在 `d2x/`) + +| 设施 | 说明 | +|---|---| +| `d2x::check(cond, "原文")` / `check_eq(a, b, "a == b")` | 第三参是给学习者看的表达式原文(迁移脚本自动从宏参数生成,教学输出零漂移);`std::formattable` 探测转印值(SFINAE 安全,requires 里直接写 std::format 会踩未特化 formatter 的 static_assert) | +| `D2X_YOUR_ANSWER` | **纯约定,无定义**。裸标识符的编译报错正好指着要填的位置 | +| `d2x::wait()` | 路障;记录后继续执行(后续检查点照跑) | +| `d2x::dont_delete_this(expr)` | 恒等透传(旧 D2X_DONT_DELETE_THIS) | +| 退出码 | 首次调用注册 atexit:有失败检查点或未拆 wait → `_Exit(1)`。裸 `mcpp test` 因此天然能判对错 | +| 侧信道 v2 | `{"v":2,"kind":"assert","ok":…,"what":…,"expected":…,"actual":…,"file":…,"line":…}` / `{"v":2,"kind":"wait",…}`;`D2X_RESULT_FILE` 未设置时不写文件 | + +**可见输出(去 HONLY 后的日志标识——emoji 即标识,无框架前缀)**: + +``` +✅ | a == a1 (1 == 1) 绿 +❌ | a == b (1 == 2) --> src/cpp11/tests/.../0.cpp:38 红 +🚧 | Delete the d2x::wait() to continue --> : 黄 +``` + +失败/路障行带定位;路径经 cwd 剥离尽量以仓库相对形式展示(定位用的 +绝对路径仍走侧信道,展示归展示、定位归定位)。 + +**判定顺序(注意与设计稿 §5 的一处刻意调整)**:失败断言 → fail;`wait` → blocked; +退出码非 0 → fail;无侧信道 → 退出码 0 即 pass。`wait` 判定**先于**退出码—— +新 harness 里 wait 会把退出码顶成 1,按旧顺序 blocked 会全部误判成 fail。 + +**教学细节**:`import std` 不带宏——需要 `NULL` 的课(12-nullptr)显式 +`#include ` 并注释原因;全局 `int8_t` 等别名要写 `std::int8_t`。 + +## 4. 依赖的 mcpp 能力(本地分支 feat/test-isolation-json) + +逐测试编译隔离(Phase A 包级/Phase B 每测试独立 ninja goal)、`mcpp test `、 +`--message-format json`、tests 相对路径命名、`[build].flags` glob 覆盖测试 TU、 +`merged_environ` 剥离私有 glibc loader 路径(嵌套段错误根治,d2mcpp `runner.cppm` +的 `unsetenv` workaround 已删;d2x `platform.cppm` 的保留——它还保护 editor 等 +非 mcpp 子进程)。**mcpp 发版并更新 xlings pin 前,CI 会失败,属预期。** + +## 5. 验证结果(2026-07-23,musl 静态 mcpp) + +| 项 | 结果 | +|---|---| +| e2e(`d2x/buildtools/tests/e2e.sh all`) | zh 52/52、en 52/52 答案全绿;pristine 双向 0-pass;Provider 冒烟 ✓ | +| d2x 端到端 | checker 显示 0/52 → 改对自动推进 → state.json 兼容旧 id ✓ | +| d2x 仓库改动 | **零**(协议边界承诺兑现) | +| hello-mcpp | 答案已补,进入 e2e,不再 SKIP | + +## 6. 已知缺口(本轮后仍开) + +- macOS / Windows 未实测(Provider 的 `_popen` 分支、mcpp test 三能力的 Windows 路径) +- 编译错误未结构化成协议 diagnostics(原始文本透传,独立增量) +- Provider 无单测(discovery 推导/JSON 解析仅被 e2e 间接覆盖) +- cpp17/20/23 目录尚无练习(撰稿侧工作,脚手架已就绪) diff --git a/.agents/docs/2026-07-23-migration-plan.md b/.agents/docs/2026-07-23-migration-plan.md new file mode 100644 index 0000000..0b654a4 --- /dev/null +++ b/.agents/docs/2026-07-23-migration-plan.md @@ -0,0 +1,29 @@ +# d2mcpp「练习即测试」迁移 — Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 按 `2026-07-23-exercises-as-tests-design.md` 完成 d2mcpp 侧迁移:无宏 harness、`cpp*/tests/` 目录、Provider 瘦身为 `mcpp test --message-format json` 的薄壳,并用本地 musl mcpp 二进制端到端打通 `d2x checker`。 + +**Architecture:** 试点先行——先迁 cpp14(2 题)验证整条链(harness 模块导入、mcpp test 命名/隔离/JSON、Provider 判定合并、d2x checker),再脚本化批量迁移 cpp11×49 + en×52 + solutions×51。mcpp 依赖本地分支 `feat/test-isolation-json` 的 musl 静态二进制(`ls -dt mcpp/target/x86_64-linux-musl/*/bin/mcpp | head -1`),通过 PATH 前置注入。 + +**Tech Stack:** C++23 modules(harness/练习)、C++26(Provider)、bash(迁移脚本 + e2e)。 + +## Global Constraints + +- 分支:`feat/mcpp-provider`(d2mcpp)、`feat/exercise-framework-protocol`(d2x),均不推送,本地交付。 +- musl mcpp 注入方式:`export PATH="$SHIM:$PATH"`,SHIM 目录里只有 mcpp 符号链接。 +- 练习可见输出格式(`[HONLY LOGI]: - ✅ | ...`)**保持不变**——book 里引用了它,格式漂移=文档漂移。 +- 侧信道 v2:每行加 `"v":2`;assert 增可选 `"what"`;判定顺序与设计稿 §5 一致。 +- id/order/chapter 推导公式不变(`cpp11-00-auto-and-decltype-0`,order=rank×100000+章×100+序)。 +- Provider 协议事件(describe/exercise/stage/output/verdict/error)一个字段都不改——d2x 零改动是设计承诺。 +- e2e 两道防线(pass==0 防空转、脏树拒绝)原样保留。 + +## Tasks + +- [x] **T1 harness/ 新包**:顶层 `harness/`,纯模块 `d2x.harness`(check/check_eq/wait,source_location,`what` 可选参),atexit 退出码(失败或 wait 未拆→`_Exit(1)`),侧信道 v2 内联进模块(report.hpp 内容并入,include 路径退役)。单测:临时 fixture 直接 mcpp test。 +- [x] **T2 试点 cpp14**:`cpp14/mcpp.toml`(dep harness path)+ `cpp14/tests/00-generic-lambdas/{0,1}.cpp`(内容转换:include→import,宏→函数)+ solutions 镜像;根 workspace 更新;`mcpp test -p cpp14` 原生验证(未完成→fail,答案→pass)。 +- [x] **T3 Provider 瘦身**:discovery 扫 `cpp*/tests`+`intro/tests`(en 前缀 `en/`);check = spawn `mcpp test --message-format json -p ` + 读侧信道 + 合并判定;manifest.cppm 删除;runner.cppm 换成 mcpp-test 解析器;unsetenv workaround 删(mcpp c1bf311 已根治)。 +- [x] **T4 批量迁移**:脚本迁 cpp11×49 + en/×52 + intro(hello-mcpp)+ solutions;两道特殊 cxxflags 题改用 `[build] flags = [{glob=...}]`(先验证 glob 对 tests/ 生效,不生效则保留头部指令+Provider 透传······不,tests 由 mcpp 驱动,必须 toml 承载,验证是硬前提);删 dslings/。 +- [x] **T5 e2e.sh 重写**:两次全量 `mcpp test`(pristine 全 fail + overlay 全 pass)×zh/en + Provider 协议冒烟(枚举 52、check 单题事件流);hello-mcpp 补答案入 e2e。 +- [x] **T6 d2x 端到端**:构建 d2x(feat/exercise-framework-protocol,musl mcpp on PATH),`d2x checker` 跑通新链路;.d2x.json 不变。 +- [x] **T7 文档收尾**:book 路径 sed、authoring skill、CI workflow(注明需 mcpp 下一发版)、参考文档更新记录、CHANGELOG 式提交。 diff --git a/.agents/skills/d2mcpp-authoring/SKILL.md b/.agents/skills/d2mcpp-authoring/SKILL.md index 67abbfb..c40ddaa 100644 --- a/.agents/skills/d2mcpp-authoring/SKILL.md +++ b/.agents/skills/d2mcpp-authoring/SKILL.md @@ -3,23 +3,23 @@ name: d2mcpp-authoring description: >- Authoring conventions, design principles, and file formats for the d2mcpp (D2X) Modern C++ tutorial project. Use this whenever you add or edit a C++ - language-feature lesson — a book chapter, a dslings exercise, a reference - solution, or when registering them in SUMMARY/xmake/changelog. Trigger it for - any request like "add a chapter for X", "write a dslings exercise for fold + language-feature lesson — a book chapter, an exercise, a reference + solution, or when registering them in SUMMARY/changelog. Trigger it for + any request like "add a chapter for X", "write an exercise for fold expressions", "add the constexpr lesson", "fill the cpp14 section", or - anything touching book/src, book/en/src, dslings/, or solutions/. Even small - edits should follow these conventions so the bilingual + book/code/checker - artifacts stay in sync. + anything touching book/src, book/en/src, src/ (exercises), or solutions/. + Even small edits should follow these conventions so the bilingual + + book/code/checker artifacts stay in sync. --- # d2mcpp (D2X) Authoring Conventions d2mcpp teaches **Modern C++ core language features** through a tightly coupled -quartet: **Book (mdBook) + Code (dslings exercises) + Solution + Auto-checker -(`d2x checker`)**, all of it **bilingual (zh + en)**. A "lesson" is never one +quartet: **Book (mdBook) + Code (exercises-as-tests) + Solution + Auto-checker +(`d2x checker` / native `mcpp test`)**, all of it **bilingual (zh + en)**. A "lesson" is never one file — it is a coordinated set across several directories. The cardinal sin here is producing a half-set (a chapter with no exercise, a zh file with no en -counterpart, an exercise not registered in xmake). This skill exists so every +counterpart, an exercise missing from solutions/). This skill exists so every lesson lands complete and consistent. Read `references/anatomy.md` for the full directory map and the exact list of @@ -46,9 +46,11 @@ Honor that axis: forward — they are not chapter-worthy on their own. Examples: `auto x{1}` deduction change, `std::is_pod` deprecation pointer, guaranteed copy elision remark, P0136 inheriting-constructor semantics fix. -- **Compile each chapter at its introduction standard.** Do not globally pin a - newer standard. If one exercise genuinely needs a later standard, make it an - **explicit, commented exception** in xmake — never a bare `-- TODO` hack. +- **All exercises compile as c++23** — the `cppNN/` directory denotes when the + feature was *introduced*, not the compile flags. Teach the introduction-era + shape through content and assertions (an untested teaching point disappears + silently). If one exercise needs special flags, declare a per-glob entry in + the member's `src//mcpp.toml` `[build].flags` — never a bare `TODO` hack. Background and the full per-feature evolution analysis live in `.agents/docs/2026-06-08-cpp11-feature-evolution-and-cxx20-baseline.md`. Consult @@ -67,11 +69,10 @@ When adding a feature numbered `NN` with slug `topic` (e.g. `06-scoped-enums`): 1. `book/src//NN-topic.md` — zh chapter 2. `book/en/src//NN-topic.md` — en chapter (translate prose, keep code identical) -3. `dslings//NN-topic-K.cpp` — one or more exercises (`K` = 0,1,2…), zh comments -4. `dslings/en//NN-topic-K.cpp` — en exercises (translate comments only) -5. `solutions//NN-topic-K.cpp` — reference solution per exercise -6. Register each exercise target in `dslings//xmake.lua` -7. Register each solution target in `solutions/xmake.lua` +3. `src//tests/NN-topic/K.cpp` — one or more exercises (`K` = 0,1,2…), zh comments +4. `src/en//tests/NN-topic/K.cpp` — en exercises (translate comments only) +5. `solutions//NN-topic/K.cpp` — reference solution per exercise (zh/en 共用) +6. (nothing to register — exercises are tests, discovered by directory convention) 8. Add the chapter line to **both** `book/src/SUMMARY.md` and `book/en/src/SUMMARY.md` 9. Add a changelog entry to **both** `book/src/changelog.md` and `book/en/src/changelog.md` @@ -81,9 +82,9 @@ exact registration snippets and SUMMARY/changelog line formats. ## Naming and numbering - Chapter/exercise prefix is a **two-digit** sequence `NN` within the standard - section; slug is **kebab-case** and matches book + dslings + solutions. -- Exercises split into `-0`, `-1`, … by sub-topic; a single-exercise chapter has - no numeric suffix on the dslings target name but the file is still `NN-topic.cpp`. + section; slug is **kebab-case** and matches book + tests + solutions. +- Exercises split into `0.cpp`, `1.cpp`, … by sub-topic inside the chapter + directory `src//tests/NN-topic/`; a single-exercise chapter is just `0.cpp`. - The **`d2x checker `** name is the slug (and `-1`, `-2` for later exercises) — it omits the `NN-` prefix. Keep checker names, file names, and book references mutually consistent. @@ -106,7 +107,7 @@ Use `assets/chapter.zh.md` / `assets/chapter.en.md`. Required structure, in orde 6. `## 二、真实案例` corroborates the feature with **real, verbatim STL code** quoted from the in-repo `msvc-stl/` basis — see "The 真实案例 section" below. 7. `## 四、练习代码` lists **every** exercise topic of the chapter (`-0`, `-1`, …, - matching the dslings/xmake count) with dslings links as an index, but the checker + matching the dslings file count) with dslings links as an index, but the checker block shows only the **single entry** command `d2x checker ` — `d2x` auto- advances through the remaining exercises, so do NOT list one command per exercise. Then a `### 练习交流讨论` link to the chapter's forum thread. Each exercise's own @@ -142,7 +143,7 @@ the pinned upstream commit and how to refresh it). Rules: - Every chapter should carry this section. If a feature genuinely has no representative usage in the STL implementation, omit it and state why in the PR. -## dslings exercise format +## Exercise format (exercises are tests) Use `assets/exercise.cpp`. Essentials: @@ -150,16 +151,23 @@ Use `assets/exercise.cpp`. Essentials: `Exercise/练习:` line (` | NN - topic | 中文小标题`), `Tips/提示:`, `Docs/文档:` (cppreference), and the `Auto-Checker/自动检测命令:` with `d2x checker `. -- `#include ` then any std headers. +- `import std;` + `import d2x;` — no `#include` unless the lesson + needs a macro from a header (e.g. `NULL` teaching needs ``; put the + include *before* the imports with a comment saying why). - `main()` seeded with **intentional errors** the learner fixes, each flagged by a numbered inline comment (`// 1.…`, `// 2.…`) telling them what to do. -- Checkpoint macros from `d2x/cpp/common.hpp`: - - `d2x_assert(cond)` / `d2x_assert_eq(a, b)` — runtime checkpoints; learners - must make them pass by fixing code, **not** by deleting the checkpoint. - - `D2X_YOUR_ANSWER` — a fill-in placeholder the learner replaces. - - `D2X_WAIT` — separates exercises; learner deletes/comments it to advance. +- Conventions (the d2x library, `import d2x;`, no macros): + - `d2x::check(cond, "原文")` / `d2x::check_eq(a, b, "a == b")` — runtime + checkpoints; the third argument is the expression text shown to learners + (c++23 has no reflection to capture it automatically — always pass it). + Learners must make checks pass by fixing code, **not** by deleting them. + - `D2X_YOUR_ANSWER` — the fill-in placeholder. It is **not defined anywhere**; + the compiler error pointing at it *is* the feature. Never define it. + - `d2x::wait()` — separates exercises; learner deletes it to advance. Put exactly one at the end of each exercise's checkpoints. - - `D2X_DONT_DELETE_THIS` — guards lines that must not be removed. + - `d2x::dont_delete_this(expr)` — guards expressions that must not be removed. +- A pure observation exercise may be **zero-dependency plain C++** (no imports) — + judged by exit code alone, copy-pasteable into Compiler Explorer. - The **en exercise translates only the comment prose**; the code stays byte-for-byte identical to the zh exercise so checker behavior matches. @@ -170,13 +178,13 @@ Use `assets/solution.cpp`. It is the corrected exercise with: - A solution header: `reference solution for: `, plus the note that it is **for CI/maintainers only, not a tutorial entry**, and a pointer back to the exercise file. -- `D2X_WAIT` removed; all checkpoints passing; unused locals silenced with +- `d2x::wait()` removed; all checkpoints passing; unused locals silenced with `(void)var;` rather than left to warn. -- Same `#include`s and structure as the exercise. +- Same imports and structure as the exercise. ## Definition of done Before claiming a lesson complete, verify the whole set exists and is wired up, and that the exercise/solution actually build & check. See `references/anatomy.md` for the verification commands (`d2x checker ` and -the xmake build) — run them; do not assert success without the output. +the mcpp build) — run them; do not assert success without the output. diff --git a/.agents/skills/d2mcpp-authoring/assets/chapter.en.md b/.agents/skills/d2mcpp-authoring/assets/chapter.en.md index 35ec161..2bf0339 100644 --- a/.agents/skills/d2mcpp-authoring/assets/chapter.en.md +++ b/.agents/skills/d2mcpp-authoring/assets/chapter.en.md @@ -12,7 +12,7 @@ | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/...) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src//NN-topic.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings//NN-topic-0.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/...) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src//NN-topic.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main//tests/NN-topic/0.cpp) | | **Why was it introduced?** @@ -60,7 +60,7 @@ - @@ -67,8 +67,8 @@ ### 练习代码主题 -- 0 - [<练习 0 主题>](https://github.com/mcpp-community/d2mcpp/blob/main/dslings//NN-topic-0.cpp) -- 1 - [<练习 1 主题>](https://github.com/mcpp-community/d2mcpp/blob/main/dslings//NN-topic-1.cpp) +- 0 - [<练习 0 主题>](https://github.com/mcpp-community/d2mcpp/blob/main//tests/NN-topic/0.cpp) +- 1 - [<练习 1 主题>](https://github.com/mcpp-community/d2mcpp/blob/main//tests/NN-topic/1.cpp) ### 练习代码自动检测命令 diff --git a/.agents/skills/d2mcpp-authoring/assets/exercise.cpp b/.agents/skills/d2mcpp-authoring/assets/exercise.cpp index 0ca3d10..439b252 100644 --- a/.agents/skills/d2mcpp-authoring/assets/exercise.cpp +++ b/.agents/skills/d2mcpp-authoring/assets/exercise.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings//NN-topic-K.cpp +// file: src//tests/NN-topic/K.cpp // // Exercise/练习: | NN - topic | <中文小标题> // @@ -14,23 +14,23 @@ // d2x checker // -#include - -#include +import std; +import d2x; int main() { // 1.<要修复的点>: <说明,例如:修复这个编译错误 / 改成正确类型> int a = 1.1; // <提示> - d2x_assert_eq(a, 1.1); // 运行时检查点:需修复代码使其通过(不要删除检查点) + d2x::check_eq(a, 1.1, "a == 1.1"); // 运行时检查点:需修复代码使其通过(不要删除检查点) - // 2.<填空点>: 用正确的代码替换 D2X_YOUR_ANSWER + // 2.<填空点>: 用正确的代码替换 D2X_YOUR_ANSWER(它不是宏,只是个没人定义的名字, + // 编译器会指着它报错 —— 那就是要填的地方) D2X_YOUR_ANSWER b = a; // <提示:给 b 一个合适的类型> - d2x_assert_eq(b, 1); + d2x::check_eq(b, 1, "b == 1"); - D2X_WAIT // 删除或注释掉本宏进入下一个练习 + d2x::wait(); // 路障:读完本课删除这一行,进入下一个练习 return 0; } diff --git a/.agents/skills/d2mcpp-authoring/assets/solution.cpp b/.agents/skills/d2mcpp-authoring/assets/solution.cpp index 65857f3..9498f31 100644 --- a/.agents/skills/d2mcpp-authoring/assets/solution.cpp +++ b/.agents/skills/d2mcpp-authoring/assets/solution.cpp @@ -1,29 +1,28 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// reference solution for: dslings//NN-topic-K.cpp +// reference solution for: src//tests/NN-topic/K.cpp // // 用途: 仅给 CI 与维护者参考使用,不是教程入口。 -// 教程练习入口: dslings//NN-topic-K.cpp +// 教程练习入口: src//tests/NN-topic/K.cpp // -#include - -#include +import std; +import d2x; int main() { // 1.<已修复>: 说明保持与练习一致,但代码为正确版本 double a = 1.1; - d2x_assert_eq(a, 1.1); + d2x::check_eq(a, 1.1, "a == 1.1"); // 2.<已填空> - double b = a; + int b = a; (void)b; // 用 (void) 抑制未使用告警,不要留下会触发 warning 的代码 - d2x_assert_eq(b, 1.1); + d2x::check_eq(b, 1, "b == 1"); - // 注意: 参考答案中删除 D2X_WAIT,且所有检查点均通过 + // 注意: 参考答案中删除 d2x::wait(),且所有检查点均通过 return 0; } diff --git a/.agents/skills/d2mcpp-authoring/references/anatomy.md b/.agents/skills/d2mcpp-authoring/references/anatomy.md index cdd4dee..e40daa0 100644 --- a/.agents/skills/d2mcpp-authoring/references/anatomy.md +++ b/.agents/skills/d2mcpp-authoring/references/anatomy.md @@ -16,12 +16,10 @@ book/en/src/SUMMARY.md # en TOC (register here) book/src/changelog.md # zh changelog (add entry) book/en/src/changelog.md # en changelog (add entry) -dslings//NN-topic-K.cpp # zh exercise(s) -dslings/en//NN-topic-K.cpp # en exercise(s) -dslings//xmake.lua # register exercise target(s) +src//tests/NN-topic/K.cpp # zh exercise(s) — no registration needed +src/en//tests/NN-topic/K.cpp # en exercise(s) — no registration needed -solutions//NN-topic-K.cpp # reference solution(s) -solutions/xmake.lua # register solution target(s) (includes ) +solutions//NN-topic/K.cpp # reference solution(s), zh/en 共用 ``` Repo-level shared basis (NOT per-lesson, created once, never edited by hand): @@ -37,54 +35,53 @@ The `## 二、真实案例` section of every chapter links into `msvc-stl/` for verbatim STL excerpt; you do not add files here per lesson — only refresh the snapshot via `msvc-stl/SOURCE.md` when needed. -A new `` section that does not exist yet also needs: an `includes("")` -line wired from `dslings/xmake.lua` and `solutions/xmake.lua`, a `dslings//` -and `dslings/en//` directory, a `solutions//` directory, and the -section heading in both `SUMMARY.md` files (e.g. `# C++14核心语言特性` / -`# C++14 Core Language Features`). - -## xmake registration — exercises (`dslings//xmake.lua`) - -Append one target per exercise file. Binary kind is the default; only set it -where existing siblings do. Example for a two-exercise chapter: - -```lua --- target: -NN-topic - -target("-NN-topic-0") - add_files("NN-topic-0.cpp") - -target("-NN-topic-1") - add_files("NN-topic-1.cpp") +A new `` section that does not exist yet needs: a `src//mcpp.toml` (copy +`src/cpp14/mcpp.toml`, change the name), `src//tests/` + `src/en//tests/` + +`solutions//` directories, the member added to the root `mcpp.toml` +workspace list (both `src/` and `src/en/`), and the section heading in both +`SUMMARY.md` files (e.g. `# C++14核心语言特性` / `# C++14 Core Language +Features`). + +## Exercise registration — there is none + +**Exercises are tests.** Each `/` is a real mcpp project and exercises are +its `tests/`; dropping `/tests/NN-topic/K.cpp` into place is the whole job. +`mcpp test -p src/` runs them natively (the report is the progress table), and +the d2x Provider (`d2x/buildtools/`) derives the exercise id, order and +chapter from the same path — one chain, no generated manifests, nothing under +`.d2x/` but learner progress. + +This is deliberate. rustlings' most expensive lesson (PR #1355) was the Rust +edition living in *two* places — the `rustc` args and `rust-project.json` — +which drifted and caused bugs. Any standalone registration file is a second +source of truth. Here the only truth is the directory layout. + +### Per-exercise compile flags + +When a lesson needs non-default flags, declare a per-glob entry in the member's +`/mcpp.toml` — `[build].flags` globs cover test TUs: + +```toml +[build] +flags = [ + { glob = "tests/NN-topic/*.cpp", cxxflags = ["-O0", "-fno-elide-constructors"] }, +] ``` -Per-target options seen in the repo, use only when the lesson needs them: +(No current exercise needs this; the capability exists for lessons that teach +observation-sensitive behavior.) -```lua -target("cpp11-04-rvalue-references") - set_optimize("none") - add_cxxflags("-fno-elide-constructors") -- observe moves; note C++17 guaranteed elision can't be disabled - add_files("04-rvalue-references.cpp") -``` +### C++ standard -If an exercise needs a non-default standard, make it an **explicit, commented -exception** — never a bare TODO: +All exercises compile as **c++23** (`standard` in each member's `mcpp.toml`). +The `cppNN/` directories denote *when a feature was introduced* — they do not +change compile flags. -```lua -target("cppNN-NN-topic-0") - set_languages("c++17") -- exception: - add_files("NN-topic-0.cpp") -``` - -The default standard is set at the top of `dslings//xmake.lua`. Per the -design principle, that should be the **introduction standard** of the section -(e.g. `set_languages("c++11")` for `cpp11`). Avoid per-host standard forks; if -one is unavoidable, comment why. - -## xmake registration — solutions (`solutions/xmake.lua` + `solutions//xmake.lua`) +## Solution registration — there is none either -Mirror the exercise targets so CI builds the reference solutions too. Follow the -existing pattern in `solutions//xmake.lua`. +Drop the file at `solutions//NN-topic/K.cpp` (zh/en share one solution). +CI swaps it over the exercise and asserts it passes; see +`d2x/buildtools/tests/e2e.sh`. ## SUMMARY registration @@ -113,8 +110,14 @@ to an absolute `YYYY/MM/DD`. Run from the project root; report real output, do not assert success blind: ```bash -# build the exercise + solution targets (lang defaults come from xmake) -xmake f -c >/dev/null && xmake build cppNN-NN-topic-0 +# run the exercise natively (fastest loop while authoring) +mcpp test -p src/ NN-topic + +# check it through the Provider path (exactly what `d2x checker` consumes) +mcpp run -q -p d2x/buildtools -- check cppNN-NN-topic-0 + +# or validate every exercise + solution at once (zh + en) +bash d2x/buildtools/tests/e2e.sh all # drive the auto-checker against the exercise (expects the unsolved exercise to fail, # the solution to pass) — name omits the NN- prefix diff --git a/.d2x.json b/.d2x.json index 7424e6b..aa6602b 100644 --- a/.d2x.json +++ b/.d2x.json @@ -1,7 +1,7 @@ { "version": "0.1.1", - "buildtools": "xmake d2x-buildtools", - "lang": "en", + "buildtools": "mcpp run -q -p d2x/buildtools --", + "lang": "zh", "llm": { "api_key": "", "api_url": "https://api.deepseek.com/v1", @@ -9,4 +9,4 @@ "system_prompt": "" }, "ui_backend": "tui" -} \ No newline at end of file +} diff --git a/.github/workflows/dslings-ref-ci.yml b/.github/workflows/dslings-ref-ci.yml index ab21712..37279cc 100644 --- a/.github/workflows/dslings-ref-ci.yml +++ b/.github/workflows/dslings-ref-ci.yml @@ -1,115 +1,81 @@ -name: Validate dslings reference solutions +name: Validate exercises and reference solutions + +# 断言两件事,缺一不可: +# 1. 每个练习「未完成时」不通过 —— 否则学习者会被直接跳过,练习形同虚设 +# 2. 每个参考答案「放进去后」通过 —— 否则参考答案本身是错的 +# +# 练习即测试:e2e 走 `mcpp test`,与 `d2x checker` 内部的 Provider 是同一条 +# 链路,所以 CI 绿灯等价于学习者本地能跑通,而不是另一条平行的构建路径。 +# +# 依赖 mcpp >= 0.0.104(测试能力批次:逐测试隔离 / 过滤 / --list / --timeout / +# --message-format json / tests 吃 [build].flags)。pin 见 .xlings.json。 on: push: branches: ["main"] paths: - - "dslings/**" + - "src/**" - "solutions/**" - "d2x/**" - - "xmake.lua" + - "mcpp.toml" + - ".d2x.json" - ".github/workflows/dslings-ref-ci.yml" pull_request: paths: - - "dslings/**" + - "src/**" - "solutions/**" - "d2x/**" - - "xmake.lua" + - "mcpp.toml" + - ".d2x.json" - ".github/workflows/dslings-ref-ci.yml" workflow_dispatch: jobs: - build-and-run-reference: + validate-exercises: runs-on: ubuntu-latest env: - XLINGS_VERSION: "0.4.14" + XLINGS_VERSION: "0.4.51" + XLINGS_NON_INTERACTIVE: "1" steps: - uses: actions/checkout@v4 - - name: Install Xlings ${{ env.XLINGS_VERSION }} + # 官方一键安装脚本自带镜像回退。手动 curl GitHub release 包会被 + # release CDN 的间歇性 504 打断。 + - name: Install xlings ${{ env.XLINGS_VERSION }} run: | set -eu - curl -fsSL "https://github.com/openxlings/xlings/releases/download/v${XLINGS_VERSION}/xlings-${XLINGS_VERSION}-linux-x86_64.tar.gz" \ - | tar -xzf - -C /tmp - /tmp/xlings-${XLINGS_VERSION}-linux-x86_64/bin/xlings self install + curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh \ + | bash -s "v${XLINGS_VERSION}" echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH" - - name: Install xmake (via xlings) - run: xlings install xmake -y - - - name: xmake config - run: xmake f -y - - # Following steps go through the SAME `xmake d2x-buildtools` plugin - # path that `d2x checker` uses internally (see d2x/buildtools/xmake/main.lua). - # This way the CI exercises the real d2x integration code path, not a - # parallel xmake-only path. A passing CI here is what a learner would - # see if they ran `d2x checker cpp11-XX-feat-K-ref` locally. - - - name: List all *-ref targets via d2x-buildtools - id: list_ref + # 按 .xlings.json 安装 mcpp。mcpp 自带工具链沙箱,无需另装 gcc。 + - name: Install mcpp run: | set -eu - REF_TARGETS=$(xmake d2x-buildtools --command=list 2>/dev/null \ - | tr ' ' '\n' \ - | sed 's/@.*$//' \ - | grep -E '\-ref$' \ - | sort -u) - echo "Found $(echo "$REF_TARGETS" | wc -l) reference targets:" - echo "$REF_TARGETS" - echo "targets<> "$GITHUB_OUTPUT" - echo "$REF_TARGETS" >> "$GITHUB_OUTPUT" - echo "EOF" >> "$GITHUB_OUTPUT" + xlings update + xlings install -y - - name: Build all *-ref targets via d2x-buildtools - run: | - set -eu - while IFS= read -r tgt; do - [ -z "$tgt" ] && continue - echo "::group::build $tgt" - xmake d2x-buildtools --command=build --target="$tgt" - echo "::endgroup::" - done <<< "${{ steps.list_ref.outputs.targets }}" + - name: Build d2x Provider + run: mcpp build -p d2x/buildtools - - name: Run all *-ref targets via d2x-buildtools and assert no ❌ - run: | - set -eu - fail=0 - while IFS= read -r tgt; do - [ -z "$tgt" ] && continue - echo "::group::run $tgt" - output=$(xmake d2x-buildtools --command=run --target="$tgt" 2>&1) - echo "$output" - if echo "$output" | grep -qE '❌|Compilation/Running failed'; then - echo "::error::reference target $tgt produced a ❌ — exercise solution does not pass its own asserts" - fail=1 - fi - if echo "$output" | grep -q 'Delete the D2X_WAIT to continue'; then - echo "::error::reference target $tgt still contains D2X_WAIT — remove it from the solution" - fail=1 - fi - echo "::endgroup::" - done <<< "${{ steps.list_ref.outputs.targets }}" - exit $fail + - name: Validate exercises and solutions (zh + en) + run: bash d2x/buildtools/tests/e2e.sh all - - name: Verify dslings ↔ solutions filename parity + - name: Verify exercises ↔ solutions filename parity run: | set -eu - # Every dslings/{cpp,hpp} file should have a matching solutions/ counterpart + # en/ 镜像跳过 —— 参考答案与语言无关,两边共用同一份 missing=0 - while IFS= read -r f; do - rel="${f#dslings/}" - # Skip the en/ mirror — solutions are language-neutral - case "$rel" in - en/*) continue ;; - esac - if [ ! -f "solutions/$rel" ]; then - echo "::warning::missing solutions/$rel (paired with dslings/$rel)" + for f in $(find intro/tests cpp*/tests -name '*.cpp'); do + std="${f%%/*}" + rel="${f#*/tests/}" + if [ ! -f "solutions/$std/$rel" ]; then + echo "::warning::missing solutions/$std/$rel (paired with $f)" missing=$((missing+1)) fi - done < <(find dslings -name '*.cpp' -not -path 'dslings/en/*') + done if [ "$missing" -gt 0 ]; then - echo "::warning::$missing dslings exercises do not yet have a reference solution. This is informational during the bring-up phase; tighten to error once cpp11 is fully covered." + echo "::warning::$missing 个练习尚无参考答案。铺开阶段仅作提示;覆盖完整后收紧为错误。" fi diff --git a/.gitignore b/.gitignore index 683495e..fe0b345 100644 --- a/.gitignore +++ b/.gitignore @@ -40,10 +40,14 @@ __pycache__ # d2x project files .xlings .vscode -.xmake .zed llm.config.xlings media -build .cache/ -dslings/compile_commands.json \ No newline at end of file +# d2x 学习进度与判定侧信道 +.d2x/state.json +.d2x/result.ndjson + +# mcpp 构建产物 +target/ +compile_commands.json diff --git a/.vscode/settings.json b/.vscode/settings.json index a80607e..9638d4c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,8 +8,7 @@ "C_Cpp.files.exclude": { "**/.vscode": true, - "**/build": true, - "**/.xmake": true, + "**/target": true, "**/.xlings": true, "**/.DS_Store": true }, diff --git a/.xlings.json b/.xlings.json index 66d4e23..8e71f7c 100644 --- a/.xlings.json +++ b/.xlings.json @@ -1,10 +1,12 @@ { "workspace": { - "d2x": "0.1.5", - "xmake": "3.0.7", + "d2x": "2026.07.24.1", "mdbook": "0.4.43", "code": "", - "gcc": { "linux": "15.1.0" }, - "mingw-w64": { "windows": "13.0.0" } + "mcpp": { + "linux": "0.0.104", + "macosx": "0.0.104", + "windows": "0.0.104" + } } -} \ No newline at end of file +} diff --git a/README.md b/README.md index a6a8253..ddab1b3 100644 --- a/README.md +++ b/README.md @@ -67,12 +67,15 @@ irm https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_i ```bash -xlings install d2x -y -d2x install d2mcpp +xlings install d2x -y # exercise framework CLI +d2x install d2mcpp # get the course, environment auto-configured cd d2mcpp -d2x checker +d2x checker # practice loop: edit -> save -> auto-check -> advance +d2x status # progress overview ``` +> Exercises are real mcpp tests — `mcpp test -p src/cpp11` works too (no d2x involved). + **👉 [more details...](https://mcpp-community.github.io/d2mcpp/base/chapter_1.html)** ## Community diff --git a/README.zh.hant.md b/README.zh.hant.md index 97139d0..6a0525f 100644 --- a/README.zh.hant.md +++ b/README.zh.hant.md @@ -67,12 +67,15 @@ irm https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_i ```bash -xlings install d2x -y -d2x install d2mcpp +xlings install d2x -y # 練習框架 CLI +d2x install d2mcpp # 一鍵獲取課程,環境自動配置 cd d2mcpp -d2x checker +d2x checker # 練習循環: 編輯 -> 保存 -> 自動檢測 -> 推進 +d2x status # 進度總覽 ``` +> 練習就是真實的 mcpp 測試 —— 不經過 d2x,直接 `mcpp test -p src/cpp11` 同樣可用。 + **👉 [更多細節...](https://mcpp-community.github.io/d2mcpp/base/chapter_1.html)** ## 社區 diff --git a/README.zh.md b/README.zh.md index c88aede..8880850 100644 --- a/README.zh.md +++ b/README.zh.md @@ -67,12 +67,15 @@ irm https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_i ```bash -xlings install d2x -y -d2x install d2mcpp +xlings install d2x -y # 练习框架 CLI +d2x install d2mcpp # 一键获取课程,环境自动配置 cd d2mcpp -d2x checker +d2x checker # 练习循环: 编辑 -> 保存 -> 自动检测 -> 推进 +d2x status # 进度总览 ``` +> 练习就是真实的 mcpp 测试 —— 不经过 d2x,直接 `mcpp test -p src/cpp11` 同样可用。 + **👉 [更多细节...](https://mcpp-community.github.io/d2mcpp/base/chapter_1.html)** ## 社区 diff --git a/book/en/src/README.md b/book/en/src/README.md index 5f2b455..00dc449 100644 --- a/book/en/src/README.md +++ b/book/en/src/README.md @@ -17,7 +17,7 @@ [📚Book]: https://mcpp-community.github.io/d2mcpp [🎥Video]: https://www.bilibili.com/video/BV182MtzPEiX -[⌨️Code]: https://github.com/mcpp-community/d2mcpp/tree/main/dslings +[⌨️Code]: https://github.com/mcpp-community/d2mcpp/tree/main/src/cpp11/tests [👥X]: https://forum.d2learn.org/category/20 ## Goals diff --git a/book/en/src/base/chapter_0.md b/book/en/src/base/chapter_0.md index d933f77..de76941 100644 --- a/book/en/src/base/chapter_0.md +++ b/book/en/src/base/chapter_0.md @@ -12,7 +12,7 @@ d2mcpp is an open-source tutorial project focused on **Modern C++ Core Language - [Book: Online E-book](https://mcpp-community.github.io/d2mcpp/en) - [Video: Instructional Videos](https://youtube.com/playlist?list=PL7uow6t1QjF0ooMLkLSS96swpSuBZvoRE&si=1xHOGVIYpbzZAosI) -- [Code: Practice Code](https://github.com/mcpp-community/d2mcpp/tree/main/dslings/en) +- [Code: Practice Code](https://github.com/mcpp-community/d2mcpp/tree/main/src/cpp11/tests/en) - [X: mcpp Forum](https://forum.d2learn.org/category/20) ## Language Support diff --git a/book/en/src/base/chapter_1.md b/book/en/src/base/chapter_1.md index 9baf009..4354f9f 100644 --- a/book/en/src/base/chapter_1.md +++ b/book/en/src/base/chapter_1.md @@ -64,12 +64,29 @@ d2x checker [name] > Note: Exercise names support fuzzy matching +### View Learning Progress + +> Read-only progress overview grouped by chapter, without entering practice mode + +```bash +d2x status +``` + +### Native Mode (optional) + +> Every C++ standard directory is a real mcpp project and the exercises are its tests/ — you can practice with plain mcpp, no d2x involved: + +```bash +mcpp test -p src/en/cpp11 # progress table for the whole cpp11 section +mcpp test -p src/en/cpp11 03-trailing # run only exercises matching the name +``` + ### Sync Latest Practice Code -> Since the project is continuously updated, you can use the following command for automatic synchronization (if synchronization fails, you may need to manually update the project code using git) +> The project is continuously updated; update via git (save/commit your modified exercises first): ```bash -d2x update +git pull ``` ## 2. Automated Detection Program Introduction @@ -81,28 +98,33 @@ After entering the automated code practice environment using `d2x checker`, the ```cpp // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/hello-mcpp.cpp +// file: src/intro/tests/hello-mcpp.cpp // // Exercise: Automated Code Practice Tutorial // // Tips: -// This project uses the xlings tool to build automated code practice projects. Execute -// d2x checker in the project root directory to enter "compiler-driven development mode" -// for automatic exercise code detection. -// You need to modify errors in the code based on console error messages and hints. -// When all compilation errors and runtime checkpoints are fixed, you can delete or comment -// out the D2X_WAIT macro in the code to automatically proceed to the next exercise. +// This is an "exercises are tests" automated practice project. Two modes of use: +// +// d2x checker guided mode: auto-detects your edits, passing advances you +// mcpp test -p src/en/intro native mode: plain mcpp — the test report IS your progress // -// - D2X_WAIT: This macro isolates different exercises. You can delete or comment it out to proceed to the next exercise. -// - d2x_assert_eq: This macro is used for runtime checkpoints. You need to fix code errors so that all -// - D2X_YOUR_ANSWER: This macro indicates code that needs modification, typically used for code completion (replace this macro with correct code) +// Fix the code based on console error messages. There are only three conventions: +// +// - D2X_YOUR_ANSWER: the fill-in-the-blank placeholder — replace it with correct +// code. It is not a macro, just a name nobody defines, so the compiler error +// points exactly at the blank +// - d2x::check / d2x::check_eq: runtime checkpoints — fix the code so every +// check passes (do not delete the checkpoints) +// - d2x::wait(): the barrier between exercises — delete it once you have read +// the lesson to really finish it // // Auto-Checker Command: // // d2x checker hello-mcpp // -#include +import std; +import d2x; // You can observe "real-time" changes in the console when modifying code @@ -112,13 +134,13 @@ int main() { int a = 1.1; // 1. Fix this runtime error, change int to double to pass the check - d2x_assert_eq(a, 1.1); // 2. Runtime checkpoint, need to fix code to pass all checkpoints (cannot directly delete checkpoint code) + d2x::check_eq(a, 1.1, "a == 1.1"); // 2. Runtime checkpoint, need to fix code to pass all checkpoints (cannot directly delete checkpoint code) D2X_YOUR_ANSWER b = a; // 3. Fix this compilation error, give b an appropriate type - d2x_assert_eq(b, 1); // 4. Runtime checkpoint 2 + d2x::check_eq(b, 1, "b == 1"); // 4. Runtime checkpoint 2 - D2X_WAIT // 5. Delete or comment out this macro to proceed to the next exercise (project formal code practice) + d2x::wait(); // 5. Delete or comment out this line to proceed to the next exercise (project formal code practice) return 0; } @@ -127,23 +149,23 @@ int main() { **Console Output and Explanation** ```bash -🌏Progress: [>----------] 0/10 -->> Shows current exercise progress +🌏Progress: [>----------] 0/52 -->> Shows current exercise progress -[Target: 00-0-hello-mcpp] - normal -->> Current exercise name +[Exercise: hello-mcpp] -->> Current exercise name -❌ Error: Compilation/Running failed for dslings/hello-mcpp.cpp -->> Shows detection status +❌ Error: Compilation/Running failed for src/en/intro/tests/hello-mcpp.cpp -->> Shows detection status The code exist some error! ----------C-Output--------- - Compiler output information -[HONLY LOGW]: main: dslings/hello-mcpp.cpp:24 - ❌ | a == 1.1 (1 == 1.100000) -->> Error hint and location (line 24) -[HONLY LOGW]: main: dslings/hello-mcpp.cpp:26 - 🥳 Delete the D2X_WAIT to continue... +---------Output--------- - Compile/run output information +❌ | a == 1.1 (1 == 1.1) --> src/en/intro/tests/hello-mcpp.cpp:46 -->> Error hint and location (line 46) +🚧 | Delete the d2x::wait() to continue --> src/en/intro/tests/hello-mcpp.cpp:52 AI-Tips-Config: https://xlings.d2learn.org/en/documents/d2x/intro.html -->> AI hints (requires configuring large model key, optional) ---------E-Files--------- -dslings/hello-mcpp.cpp -->> Current detected file +src/intro/tests/hello-mcpp.cpp -->> Current detected file ------------------------- Homepage: https://github.com/openxlings/xlings @@ -158,7 +180,7 @@ Edit the `lang` attribute in the project configuration file `.d2x.json`. `zh` co ```bash { "version": "0.1.1", - "buildtools": "xmake d2x-buildtools", + "buildtools": "mcpp run -q -p d2x/buildtools --", "lang": "en", ... } @@ -168,16 +190,18 @@ Edit the `lang` attribute in the project configuration file `.d2x.json`. `zh` co If you prefer to use Neovim as your editor with LSP (clangd) support, you can configure it as follows: -**1. Edit the `editor` attribute in the project configuration file `config.xlings` and set it to `nvim` (or `zed`)** +**1. Edit the `editor` field in the project configuration file `.d2x.json` and set it to `nvim` (or `zed`)** -```bash -d2x = { - checker = { - name = "dslings", - editor = "nvim", -- option: vscode, nvim, zed - }, +```json +{ + "buildtools": "mcpp run -q -p d2x/buildtools --", + "editor": "nvim", + ... +} ``` +> When unset, d2x falls back to `$VISUAL` → `$EDITOR` → `code`; a `{file}` placeholder is supported; an explicit empty string disables auto-open. + **2. Run the one-click dependency installation and environment configuration command in the project root directory** ```bash diff --git a/book/en/src/cpp11/00-auto-and-decltype.md b/book/en/src/cpp11/00-auto-and-decltype.md index b013da0..f0b6df7 100644 --- a/book/en/src/cpp11/00-auto-and-decltype.md +++ b/book/en/src/cpp11/00-auto-and-decltype.md @@ -12,7 +12,7 @@ auto and decltype are powerful **type deduction** tools introduced in C++11. The | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference-auto](https://en.cppreference.com/w/cpp/language/auto) / [cppreference-decltype](https://en.cppreference.com/w/cpp/language/decltype) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/00-auto-and-decltype.md) | [Video Explanation](https://www.bilibili.com/video/BV1EzJs6HEf7) / [Exercise Walkthrough](https://www.bilibili.com/video/BV1xkdYYUEyH) | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/00-auto-and-decltype-0.cpp) | | +| [cppreference-auto](https://en.cppreference.com/w/cpp/language/auto) / [cppreference-decltype](https://en.cppreference.com/w/cpp/language/decltype) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/00-auto-and-decltype.md) | [Video Explanation](https://www.bilibili.com/video/BV1EzJs6HEf7) / [Exercise Walkthrough](https://www.bilibili.com/video/BV1xkdYYUEyH) | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/00-auto-and-decltype/0.cpp) | | **Why were they introduced?** @@ -252,12 +252,12 @@ decltype( (b) ) // Deduction result is int & ### Practice Topics -- 0 - [Declaration & Definition](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/00-auto-and-decltype-0.cpp) -- 1 - [Expression Type Deduction](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/00-auto-and-decltype-1.cpp) -- 2 - [Complex Type Deduction - Iterator / Function](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/00-auto-and-decltype-2.cpp) -- 3 - [Function Return Type Deduction](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/00-auto-and-decltype-3.cpp) -- 4 - [Class/Struct Member Type Deduction](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/00-auto-and-decltype-4.cpp) -- 5 - [const & Reference Stripping and Preservation](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/00-auto-and-decltype-5.cpp) +- 0 - [Declaration & Definition](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/00-auto-and-decltype/0.cpp) +- 1 - [Expression Type Deduction](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/00-auto-and-decltype/1.cpp) +- 2 - [Complex Type Deduction - Iterator / Function](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/00-auto-and-decltype/2.cpp) +- 3 - [Function Return Type Deduction](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/00-auto-and-decltype/3.cpp) +- 4 - [Class/Struct Member Type Deduction](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/00-auto-and-decltype/4.cpp) +- 5 - [const & Reference Stripping and Preservation](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/00-auto-and-decltype/5.cpp) ### Auto-Checker Commands diff --git a/book/en/src/cpp11/01-default-and-delete.md b/book/en/src/cpp11/01-default-and-delete.md index 4c6466f..72ddfff 100644 --- a/book/en/src/cpp11/01-default-and-delete.md +++ b/book/en/src/cpp11/01-default-and-delete.md @@ -12,7 +12,7 @@ | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/function#Deleted_functions) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/01-default-and-delete.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/01-default-and-delete-0.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/function#Deleted_functions) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/01-default-and-delete.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/01-default-and-delete/0.cpp) | | **Why were they introduced?** @@ -179,9 +179,9 @@ The real design value of `= default` / `= delete` shows up in combination with t ### Practice Topics -- 0 - [Explicitly control constructor generation behavior](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/01-default-and-delete-0.cpp) -- 1 - [Implement a non-copyable but movable UniquePtr](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/01-default-and-delete-1.cpp) -- 2 - [Use = delete to block a specific parameter-type overload](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/01-default-and-delete-2.cpp) +- 0 - [Explicitly control constructor generation behavior](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/01-default-and-delete/0.cpp) +- 1 - [Implement a non-copyable but movable UniquePtr](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/01-default-and-delete/1.cpp) +- 2 - [Use = delete to block a specific parameter-type overload](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/01-default-and-delete/2.cpp) ### Practice Code Auto-detection Command diff --git a/book/en/src/cpp11/02-final-and-override.md b/book/en/src/cpp11/02-final-and-override.md index 2d44627..c79dc24 100644 --- a/book/en/src/cpp11/02-final-and-override.md +++ b/book/en/src/cpp11/02-final-and-override.md @@ -12,7 +12,7 @@ final and override are two **context-sensitive identifiers** introduced in C++11 | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference-final](https://en.cppreference.com/w/cpp/language/final) / [cppreference-override](https://en.cppreference.com/w/cpp/language/override) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/02-final-and-override.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/02-final-and-override-0.cpp) | | +| [cppreference-final](https://en.cppreference.com/w/cpp/language/final) / [cppreference-override](https://en.cppreference.com/w/cpp/language/override) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/02-final-and-override.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/02-final-and-override/0.cpp) | | **Why were they introduced?** @@ -175,9 +175,9 @@ struct B : A { ### Practice Topics -- 0 - [Familiarize with override](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/02-final-and-override-0.cpp) -- 1 - [Familiarize with final](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/02-final-and-override-1.cpp) -- 2 - [final + Template Method - AudioPlayer / WAV / MP3 / OGG](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/02-final-and-override-2.cpp) +- 0 - [Familiarize with override](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/02-final-and-override/0.cpp) +- 1 - [Familiarize with final](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/02-final-and-override/1.cpp) +- 2 - [final + Template Method - AudioPlayer / WAV / MP3 / OGG](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/02-final-and-override/2.cpp) ### Practice Code Auto-detection Command diff --git a/book/en/src/cpp11/03-trailing-return-type.md b/book/en/src/cpp11/03-trailing-return-type.md index 1564e43..a5f7de3 100644 --- a/book/en/src/cpp11/03-trailing-return-type.md +++ b/book/en/src/cpp11/03-trailing-return-type.md @@ -12,7 +12,7 @@ The trailing return type is a new function declaration syntax introduced in C++1 | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/function) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/03-trailing-return-type.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/03-trailing-return-type.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/function) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/03-trailing-return-type.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/03-trailing-return-type/0.cpp) | | **Why was it introduced?** @@ -166,7 +166,7 @@ auto func() -> int(*)[3]; // ok: returns a pointer to an array ### Practice Topics -- 0 - [Familiarize with trailing return type - ordinary function / template / lambda](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/03-trailing-return-type.cpp) +- 0 - [Familiarize with trailing return type - ordinary function / template / lambda](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/03-trailing-return-type/0.cpp) ### Practice Code Auto-detection Command diff --git a/book/en/src/cpp11/04-rvalue-references.md b/book/en/src/cpp11/04-rvalue-references.md index 33b7fce..18098b6 100644 --- a/book/en/src/cpp11/04-rvalue-references.md +++ b/book/en/src/cpp11/04-rvalue-references.md @@ -12,7 +12,7 @@ Rvalue reference `T&&` is a new kind of reference introduced in C++11 that binds | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/reference) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/04-rvalue-references.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/04-rvalue-references.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/reference) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/04-rvalue-references.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/04-rvalue-references/0.cpp) | | **Why was it introduced?** @@ -156,7 +156,7 @@ This chapter focuses on the **value-category + reference-binding** layer. The pa ### Practice Topics -- 0 - [Use an rvalue reference to extend a temporary's lifetime and mutate it](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/04-rvalue-references.cpp) +- 0 - [Use an rvalue reference to extend a temporary's lifetime and mutate it](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/04-rvalue-references/0.cpp) ### Practice Code Auto-detection Command diff --git a/book/en/src/cpp11/05-move-semantics.md b/book/en/src/cpp11/05-move-semantics.md index f959246..d489356 100644 --- a/book/en/src/cpp11/05-move-semantics.md +++ b/book/en/src/cpp11/05-move-semantics.md @@ -12,7 +12,7 @@ Move semantics is a **resource ownership transfer** mechanism introduced in C++1 | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference-move](https://en.cppreference.com/w/cpp/utility/move) / [cppreference-move-ctor](https://en.cppreference.com/w/cpp/language/move_constructor) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/05-move-semantics.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/05-move-semantics-0.cpp) | | +| [cppreference-move](https://en.cppreference.com/w/cpp/utility/move) / [cppreference-move-ctor](https://en.cppreference.com/w/cpp/language/move_constructor) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/05-move-semantics.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/05-move-semantics/0.cpp) | | **Why was it introduced?** @@ -190,9 +190,9 @@ Similarly, a **by-value parameter** is already a fresh object, so only consider ### Practice Topics -- 0 - [Move constructor and trigger conditions - make buffer passing allocate only once](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/05-move-semantics-0.cpp) -- 1 - [Move assignment and trigger conditions - temporary / intermediate / explicit std::move](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/05-move-semantics-1.cpp) -- 2 - [Moving resources, not objects - compare object addresses vs. data pointers](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/05-move-semantics-2.cpp) +- 0 - [Move constructor and trigger conditions - make buffer passing allocate only once](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/05-move-semantics/0.cpp) +- 1 - [Move assignment and trigger conditions - temporary / intermediate / explicit std::move](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/05-move-semantics/1.cpp) +- 2 - [Moving resources, not objects - compare object addresses vs. data pointers](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/05-move-semantics/2.cpp) ### Practice Code Auto-detection Command diff --git a/book/en/src/cpp11/06-scoped-enums.md b/book/en/src/cpp11/06-scoped-enums.md index 69e1871..94de351 100644 --- a/book/en/src/cpp11/06-scoped-enums.md +++ b/book/en/src/cpp11/06-scoped-enums.md @@ -12,7 +12,7 @@ Scoped enums (`enum class` / `enum struct`) are strongly-typed enumerations intr | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/enum) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/06-scoped-enums.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/06-scoped-enums-0.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/enum) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/06-scoped-enums.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/06-scoped-enums/0.cpp) | | **Why was it introduced?** @@ -204,8 +204,8 @@ Existing codebases tend to be full of traditional enums; you don't need to rewri ### Practice Topics -- 0 - [Pitfalls of traditional enum - name clashes and implicit comparison](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/06-scoped-enums-0.cpp) -- 1 - [Basic usage of scoped enum - scoping / type safety / underlying type](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/06-scoped-enums-1.cpp) +- 0 - [Pitfalls of traditional enum - name clashes and implicit comparison](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/06-scoped-enums/0.cpp) +- 1 - [Basic usage of scoped enum - scoping / type safety / underlying type](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/06-scoped-enums/1.cpp) ### Practice Code Auto-detection Command diff --git a/book/en/src/cpp11/07-constexpr.md b/book/en/src/cpp11/07-constexpr.md index b5bd7c5..836bf5e 100644 --- a/book/en/src/cpp11/07-constexpr.md +++ b/book/en/src/cpp11/07-constexpr.md @@ -12,7 +12,7 @@ constexpr is a keyword introduced in C++11 that lifts "results that would normal | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/constexpr) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/07-constexpr.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/07-constexpr-0.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/constexpr) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/07-constexpr.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/07-constexpr/0.cpp) | | **Why was it introduced?** @@ -181,8 +181,8 @@ But here's a detail that's easy to miss: **constexpr functions are implicitly in ### Practice Topics -- 0 - [Compile-time computation basics: constexpr vs const](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/07-constexpr-0.cpp) -- 1 - [Applied compile-time computation: factorial / Sum / mysin auto lookup table](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/07-constexpr-1.cpp) +- 0 - [Compile-time computation basics: constexpr vs const](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/07-constexpr/0.cpp) +- 1 - [Applied compile-time computation: factorial / Sum / mysin auto lookup table](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/07-constexpr/1.cpp) ### Practice Code Auto-detection Command diff --git a/book/en/src/cpp11/08-literal-type.md b/book/en/src/cpp11/08-literal-type.md index 636bfbf..969bea9 100644 --- a/book/en/src/cpp11/08-literal-type.md +++ b/book/en/src/cpp11/08-literal-type.md @@ -12,7 +12,7 @@ A *literal type* (LiteralType) is the C++11 named requirement for types that are | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference-LiteralType](https://en.cppreference.com/w/cpp/named_req/LiteralType) / [cppreference-user-literal](https://en.cppreference.com/w/cpp/language/user_literal) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/08-literal-type.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/08-literal-type-0.cpp) | | +| [cppreference-LiteralType](https://en.cppreference.com/w/cpp/named_req/LiteralType) / [cppreference-user-literal](https://en.cppreference.com/w/cpp/language/user_literal) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/08-literal-type.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/08-literal-type/0.cpp) | | **Why was it introduced?** @@ -178,8 +178,8 @@ LiteralType requires at least one constexpr constructor that is **not** a copy o ### Practice Topics -- 0 - [Understand the literal-type concept - what can be constexpr](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/08-literal-type-0.cpp) -- 1 - [Define your own literal type - add a constexpr constructor to Vector](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/08-literal-type-1.cpp) +- 0 - [Understand the literal-type concept - what can be constexpr](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/08-literal-type/0.cpp) +- 1 - [Define your own literal type - add a constexpr constructor to Vector](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/08-literal-type/1.cpp) ### Practice Code Auto-detection Command diff --git a/book/en/src/cpp11/09-list-initialization.md b/book/en/src/cpp11/09-list-initialization.md index ed7d914..a887e93 100644 --- a/book/en/src/cpp11/09-list-initialization.md +++ b/book/en/src/cpp11/09-list-initialization.md @@ -12,7 +12,7 @@ List initialization is an initialization style that uses `{ arg1, arg2, ... }` l | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/list_initialization.html) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/09-list-initialization.md) | [Video Explanation](https://www.bilibili.com/video/BV1vKuQzkEo2) | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/09-list-initialization-0.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/list_initialization.html) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/09-list-initialization.md) | [Video Explanation](https://www.bilibili.com/video/BV1vKuQzkEo2) | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/09-list-initialization/0.cpp) | | **Why was it introduced?** diff --git a/book/en/src/cpp11/10-delegating-constructors.md b/book/en/src/cpp11/10-delegating-constructors.md index 98d7a47..5bf6d88 100644 --- a/book/en/src/cpp11/10-delegating-constructors.md +++ b/book/en/src/cpp11/10-delegating-constructors.md @@ -12,7 +12,7 @@ Delegating constructors are syntactic sugar introduced in C++11. Through simple | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/initializer_list.html#Delegating_constructor) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/10-delegating-constructors.md) | [Video Explanation](https://www.bilibili.com/video/BV1zft3zSEER) | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/10-delegating-constructors-0.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/initializer_list.html#Delegating_constructor) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/10-delegating-constructors.md) | [Video Explanation](https://www.bilibili.com/video/BV1zft3zSEER) | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/10-delegating-constructors/0.cpp) | | **Why was it introduced?** diff --git a/book/en/src/cpp11/11-inherited-constructors.md b/book/en/src/cpp11/11-inherited-constructors.md index f179701..18c6b32 100644 --- a/book/en/src/cpp11/11-inherited-constructors.md +++ b/book/en/src/cpp11/11-inherited-constructors.md @@ -12,7 +12,7 @@ Inherited constructors are a syntactic feature introduced in C++11 that solves t | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/using_declaration.html#Inheriting_constructors) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/11-inherited-constructors.md) | [Bili](https://www.bilibili.com/video/BV1bspBzFEEC) / [Youtube](https://youtu.be/p7vbY8XUKnY?si=GZUn9GSW68aU94A6) | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/11-inherited-constructors-0.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/using_declaration.html#Inheriting_constructors) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/11-inherited-constructors.md) | [Bili](https://www.bilibili.com/video/BV1bspBzFEEC) / [Youtube](https://youtu.be/p7vbY8XUKnY?si=GZUn9GSW68aU94A6) | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/11-inherited-constructors/0.cpp) | | **Why was it introduced?** @@ -222,9 +222,9 @@ For example, for testing environments or scenarios involving **only functional e ### Practice Code Topics -- 0 - [Familiarize with Inherited Constructors Feature](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/11-inherited-constructors-0.cpp) -- 1 - [Application in Functional Extension - StudentTest](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/11-inherited-constructors-1.cpp) -- 2 - [Application in Generic Templates - NoCopy / NoMove Behavior Constraints](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/11-inherited-constructors-2.cpp) +- 0 - [Familiarize with Inherited Constructors Feature](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/11-inherited-constructors/0.cpp) +- 1 - [Application in Functional Extension - StudentTest](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/11-inherited-constructors/1.cpp) +- 2 - [Application in Generic Templates - NoCopy / NoMove Behavior Constraints](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/11-inherited-constructors/2.cpp) ### Practice Code Auto-detection Command diff --git a/book/en/src/cpp11/12-nullptr.md b/book/en/src/cpp11/12-nullptr.md index 71b451d..a53c09b 100644 --- a/book/en/src/cpp11/12-nullptr.md +++ b/book/en/src/cpp11/12-nullptr.md @@ -12,7 +12,7 @@ | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/nullptr) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/12-nullptr.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp11/12-nullptr-0.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/nullptr) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/12-nullptr.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/src/en/cpp11/tests/12-nullptr/0.cpp) | | **Why was it introduced?** @@ -178,9 +178,9 @@ bool isEmpty = (ptr == nullptr); // true ### Practice Code Topics -- 0 - [nullptr Basic Usage](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp11/12-nullptr-0.cpp) -- 1 - [nullptr Function Overloading](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp11/12-nullptr-1.cpp) -- 2 - [nullptr Advantages in Template Programming](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp11/12-nullptr-2.cpp) +- 0 - [nullptr Basic Usage](https://github.com/mcpp-community/d2mcpp/blob/main/src/en/cpp11/tests/12-nullptr/0.cpp) +- 1 - [nullptr Function Overloading](https://github.com/mcpp-community/d2mcpp/blob/main/src/en/cpp11/tests/12-nullptr/1.cpp) +- 2 - [nullptr Advantages in Template Programming](https://github.com/mcpp-community/d2mcpp/blob/main/src/en/cpp11/tests/12-nullptr/2.cpp) ### Auto-Checker Command diff --git a/book/en/src/cpp11/13-long-long.md b/book/en/src/cpp11/13-long-long.md index e1b976d..6722c01 100644 --- a/book/en/src/cpp11/13-long-long.md +++ b/book/en/src/cpp11/13-long-long.md @@ -12,7 +12,7 @@ | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/types) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/13-long-long.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp11/13-long-long-0.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/types) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/13-long-long.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/src/en/cpp11/tests/13-long-long/0.cpp) | | **Why was it introduced?** @@ -109,8 +109,8 @@ if (bigValue > std::numeric_limits::max() || bigValue < std::numeric_limits ### Practice Code Topics -- 0 - [long long Basic Usage](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp11/13-long-long-0.cpp) -- 1 - [long long Large Number Applications and Boundary Values](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp11/13-long-long-1.cpp) +- 0 - [long long Basic Usage](https://github.com/mcpp-community/d2mcpp/blob/main/src/en/cpp11/tests/13-long-long/0.cpp) +- 1 - [long long Large Number Applications and Boundary Values](https://github.com/mcpp-community/d2mcpp/blob/main/src/en/cpp11/tests/13-long-long/1.cpp) ### Auto-Checker Command diff --git a/book/en/src/cpp11/14-type-alias.md b/book/en/src/cpp11/14-type-alias.md index d35abe8..fe1de1d 100644 --- a/book/en/src/cpp11/14-type-alias.md +++ b/book/en/src/cpp11/14-type-alias.md @@ -12,7 +12,7 @@ Type alias and alias template are important features introduced in C++11, used t | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference-type-alias](https://en.cppreference.com/w/cpp/language/type_alias) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/14-type-alias.md) | [Video Explanation]() | [Exercise Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp11/14-type-alias-0.cpp) | | +| [cppreference-type-alias](https://en.cppreference.com/w/cpp/language/type_alias) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/14-type-alias.md) | [Video Explanation]() | [Exercise Code](https://github.com/mcpp-community/d2mcpp/blob/main/src/en/cpp11/tests/14-type-alias/0.cpp) | | > Note: The `using` keyword existed before C++11, but was mainly used for namespace and class member declarations > - Declaring namespaces: `using namespace std;` @@ -192,10 +192,10 @@ struct A { ### Exercise Code Topics -- 0 - [Basic Type Alias](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp11/14-type-alias-0.cpp) -- 1 - [Complex Types and Function Pointer Aliases](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp11/14-type-alias-1.cpp) -- 2 - [Alias Template Basics](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp11/14-type-alias-2.cpp) -- 3 - [Alias Template Applications in Standard Library](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp11/14-type-alias-3.cpp) +- 0 - [Basic Type Alias](https://github.com/mcpp-community/d2mcpp/blob/main/src/en/cpp11/tests/14-type-alias/0.cpp) +- 1 - [Complex Types and Function Pointer Aliases](https://github.com/mcpp-community/d2mcpp/blob/main/src/en/cpp11/tests/14-type-alias/1.cpp) +- 2 - [Alias Template Basics](https://github.com/mcpp-community/d2mcpp/blob/main/src/en/cpp11/tests/14-type-alias/2.cpp) +- 3 - [Alias Template Applications in Standard Library](https://github.com/mcpp-community/d2mcpp/blob/main/src/en/cpp11/tests/14-type-alias/3.cpp) ### Exercise Code Auto-Check Command diff --git a/book/en/src/cpp11/15-variadic-templates.md b/book/en/src/cpp11/15-variadic-templates.md index 54a4510..06724c0 100644 --- a/book/en/src/cpp11/15-variadic-templates.md +++ b/book/en/src/cpp11/15-variadic-templates.md @@ -12,7 +12,7 @@ Variadic templates are a core template feature introduced in C++11. They allow f | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/parameter_pack) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/15-variadic-templates.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/15-variadic-templates-0.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/parameter_pack) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp11/15-variadic-templates.md) | [Video Explanation]() | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/15-variadic-templates/0.cpp) | | **Why was it introduced?** @@ -228,8 +228,8 @@ If your project allows C++17, new code should prefer fold expressions + `if cons ### Practice Topics -- 0 - [Variadic templates basics - recursive print](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/15-variadic-templates-0.cpp) -- 1 - [Variadic template sum](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/15-variadic-templates-1.cpp) +- 0 - [Variadic templates basics - recursive print](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/15-variadic-templates/0.cpp) +- 1 - [Variadic template sum](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/15-variadic-templates/1.cpp) ### Practice Code Auto-detection Command diff --git a/book/en/src/cpp11/16-generalized-unions.md b/book/en/src/cpp11/16-generalized-unions.md index 26ef95c..b2ba98b 100644 --- a/book/en/src/cpp11/16-generalized-unions.md +++ b/book/en/src/cpp11/16-generalized-unions.md @@ -15,7 +15,7 @@ The size of a union is at least large enough to hold the largest data member. | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference-union](https://cppreference.com/w/cpp/language/union.html) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/16-generalized-unions.md) | [Video Explanation]() | [Exercise Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/16-generalized-unions-0.cpp) | | +| [cppreference-union](https://cppreference.com/w/cpp/language/union.html) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/16-generalized-unions.md) | [Video Explanation]() | [Exercise Code](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/16-generalized-unions/0.cpp) | | **Why introduced?** @@ -224,9 +224,9 @@ double c = m.b; // Error: undefined behavior. ### Exercise Code Topics -- 0 - [Union Default Member Initialization](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp11/16-generalized-unions-0.cpp) -- 1 - [Union with Non-Trivial Types and Lifecycle Management](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp11/16-generalized-unions-1.cpp) -- 2 - [Tagged Discriminated Union — A Simplified std::variant with enum + union](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp11/16-generalized-unions-2.cpp) +- 0 - [Union Default Member Initialization](https://github.com/mcpp-community/d2mcpp/blob/main/src/en/cpp11/tests/16-generalized-unions/0.cpp) +- 1 - [Union with Non-Trivial Types and Lifecycle Management](https://github.com/mcpp-community/d2mcpp/blob/main/src/en/cpp11/tests/16-generalized-unions/1.cpp) +- 2 - [Tagged Discriminated Union — A Simplified std::variant with enum + union](https://github.com/mcpp-community/d2mcpp/blob/main/src/en/cpp11/tests/16-generalized-unions/2.cpp) ### Exercise Auto-Checker Command diff --git a/book/en/src/cpp11/17-pod-type.md b/book/en/src/cpp11/17-pod-type.md index defd3d7..76b92db 100644 --- a/book/en/src/cpp11/17-pod-type.md +++ b/book/en/src/cpp11/17-pod-type.md @@ -13,7 +13,7 @@ In C++, there is a corresponding category of **POD types** whose memory layout i | Book | Video | Code | Forum | | --- | --- | --- | --- | -| [cppreference-PODType](https://cppreference.com/w/cpp/named_req/PODType.html) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/17-pod-type.md) | [Video Explanation]() | [Exercise Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/17-pod-type-0.cpp) | [Discussion Forum](https://forum.d2learn.org/category/20) | +| [cppreference-PODType](https://cppreference.com/w/cpp/named_req/PODType.html) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/17-pod-type.md) | [Video Explanation]() | [Exercise Code](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/17-pod-type/0.cpp) | [Discussion Forum](https://forum.d2learn.org/category/20) | > Note: since C++20, the “PODType” notion in the standard has been marked **deprecated**. > The standard library now prefers more fine-grained categories such as `TrivialType`, `StandardLayoutType`, and `ScalarType` to describe related requirements. @@ -140,9 +140,9 @@ In new code, it is better to express constraints based on actual needs, for exam ### Exercise topics -- 0 – [Use type traits to check POD / trivial / standard-layout](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp11/17-pod-type-0.cpp) -- 1 – [Simulate byte-wise copying of a POD struct and observe the behavior](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp11/17-pod-type-1.cpp) -- 2 – [Adapt C++ message types to C interface using POD headers](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp11/17-pod-type-2.cpp) +- 0 – [Use type traits to check POD / trivial / standard-layout](https://github.com/mcpp-community/d2mcpp/blob/main/src/en/cpp11/tests/17-pod-type/0.cpp) +- 1 – [Simulate byte-wise copying of a POD struct and observe the behavior](https://github.com/mcpp-community/d2mcpp/blob/main/src/en/cpp11/tests/17-pod-type/1.cpp) +- 2 – [Adapt C++ message types to C interface using POD headers](https://github.com/mcpp-community/d2mcpp/blob/main/src/en/cpp11/tests/17-pod-type/2.cpp) ### Auto-check command diff --git a/book/en/src/cpp14/00-generic-lambdas.md b/book/en/src/cpp14/00-generic-lambdas.md index 612e50e..aea77e0 100644 --- a/book/en/src/cpp14/00-generic-lambdas.md +++ b/book/en/src/cpp14/00-generic-lambdas.md @@ -12,7 +12,7 @@ C++14 allows lambda parameters to use `auto`, turning the lambda's `operator()` | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference-lambda](https://en.cppreference.com/w/cpp/language/lambda) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp14/00-generic-lambdas.md) | [Video Explanation]() | [Exercise Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp14/00-generic-lambdas-0.cpp) | | +| [cppreference-lambda](https://en.cppreference.com/w/cpp/language/lambda) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp14/00-generic-lambdas.md) | [Video Explanation]() | [Exercise Code](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp14/tests/00-generic-lambdas/0.cpp) | | **Why introduced?** @@ -191,8 +191,8 @@ C++14 generic lambdas support parameter packs — `[](auto... xs)` accepts any n ### Exercise Code Topics -- 0 - [Basic Generic Lambda — auto parameters and type deduction](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp14/00-generic-lambdas-0.cpp) -- 1 - [Generic Lambda with STL Algorithms — sort, find, factory function](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp14/00-generic-lambdas-1.cpp) +- 0 - [Basic Generic Lambda — auto parameters and type deduction](https://github.com/mcpp-community/d2mcpp/blob/main/src/en/cpp14/tests/00-generic-lambdas/0.cpp) +- 1 - [Generic Lambda with STL Algorithms — sort, find, factory function](https://github.com/mcpp-community/d2mcpp/blob/main/src/en/cpp14/tests/00-generic-lambdas/1.cpp) ### Exercise Auto-Checker Command diff --git a/book/src/README.md b/book/src/README.md index 02c350e..831d3fd 100644 --- a/book/src/README.md +++ b/book/src/README.md @@ -17,7 +17,7 @@ [📚Book]: https://mcpp-community.github.io/d2mcpp [🎥Video]: https://www.bilibili.com/video/BV182MtzPEiX -[⌨️Code]: https://github.com/mcpp-community/d2mcpp/tree/main/dslings +[⌨️Code]: https://github.com/mcpp-community/d2mcpp/tree/main/cpp11/tests [👥X]: https://forum.d2learn.org/category/20 ## 目标 diff --git a/book/src/base/chapter_0.md b/book/src/base/chapter_0.md index a4b9d39..f925f63 100644 --- a/book/src/base/chapter_0.md +++ b/book/src/base/chapter_0.md @@ -12,7 +12,7 @@ d2mcpp是一个开源、强调代码实践的`现代C++核心语言特性`教程 - [Book: 在线电子书](https://mcpp-community.github.io/d2mcpp) - [Video: 讲解视频](https://space.bilibili.com/65858958/lists/5208246?type=season) -- [Code: 练习代码](https://github.com/mcpp-community/d2mcpp/tree/main/dslings) +- [Code: 练习代码](https://github.com/mcpp-community/d2mcpp/tree/main/cpp11/tests) - [X: mcpp论坛](https://forum.d2learn.org/category/20) ## 语言支持 diff --git a/book/src/base/chapter_1.md b/book/src/base/chapter_1.md index fabfeb8..fc7a251 100644 --- a/book/src/base/chapter_1.md +++ b/book/src/base/chapter_1.md @@ -64,12 +64,29 @@ d2x checker [name] > 注: 练习名支持模糊匹配 +### 查看学习进度 + +> 只读的进度总览,按章节聚合,不进入练习模式 + +```bash +d2x status +``` + +### 原生模式(可选) + +> 每个 C++ 标准目录都是真实的 mcpp 工程,练习就是它的 tests/——不经过 d2x,直接用 mcpp 也能练: + +```bash +mcpp test -p src/cpp11 # 整个 cpp11 的进度表(哪题绿哪题红) +mcpp test -p src/cpp11 03-trailing # 只跑名字匹配的练习 +``` + ### 同步最新的练习代码 -> 由于项目处于持续更新阶段, 可以使用下面的命令进行自动同步(如果同步失败, 可能需要手动用git进行更新项目代码) +> 项目处于持续更新阶段,更新使用 git(注意先保存/提交你已修改的练习): ```bash -d2x update +git pull ``` ## 2.自动化检测程序简介 @@ -81,26 +98,31 @@ d2x update ```cpp // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/hello-mcpp.cpp +// file: src/intro/tests/hello-mcpp.cpp // // Exercise/练习: 自动化代码练习使用教学 // // Tips/提示: -// 该项目是使用xlings工具搭建的自动化代码练习项目, 通过在项目根目录下 -// 执行 d2x checker 进入"编译器驱动开发模式"的练习代码自动检测. -// 你需要根据控制台的报错和提示信息, 修改代码中的错误. 当修复所有编译错误和 -// 运行时检查点后, 你可以删除或注释掉代码中的 D2X_WAIT 宏, 会自动进入下一个练习. +// 这是一个「练习即测试」的自动化代码练习项目。两种使用方式任选: +// +// d2x checker 引导模式: 自动检测,通过后进入下一题 +// mcpp test -p src/intro 原生模式: 直接使用 mcpp 运行, 测试报告即学习进度 +// +// 你需要根据控制台的报错和提示信息修改代码。约定只有三个: // -// - D2X_WAIT: 该宏用于隔离不同练习, 你可以删除或注释掉该宏, 进入下一个练习. -// - d2x_assert_eq: 该宏用于运行时检查点, 你需要修复代码中的错误, 使得所有 -// - D2X_YOUR_ANSWER: 该宏用于提示你需要修改的代码, 一般用于代码填空(即用正确的代码替换这个宏) +// - D2X_YOUR_ANSWER: 填空占位符 —— 用正确的代码替换它。它不是宏, +// 只是一个没人定义的名字, 所以编译器会指着它报错, 那就是要填的地方 +// - d2x::check / d2x::check_eq: 运行时检查点, 修复代码让所有检查通过 +// (不能直接删除检查点) +// - d2x::wait(): 练习之间的路障 —— 读完这一课, 删掉它才算真正完成 // // Auto-Checker/自动检测命令: // // d2x checker hello-mcpp // -#include +import std; +import d2x; // 修改代码时可以观察到控制台"实时"的变化 @@ -110,13 +132,13 @@ int main() { int a = 1.1; // 1.修复这个运行时错误, 修改int为double, 通过检查 - d2x_assert_eq(a, 1.1); // 2.运行时检查点, 需要修复代码通过所有检查点(不能直接删除检查点代码) + d2x::check_eq(a, 1.1, "a == 1.1"); // 2.运行时检查点, 需要修复代码通过所有检查点(不能直接删除检查点代码) D2X_YOUR_ANSWER b = a; // 3.修复这个编译错误, 给b一个合适的类型 - d2x_assert_eq(b, 1); // 4.运行时检查点2 + d2x::check_eq(b, 1, "b == 1"); // 4.运行时检查点2 - D2X_WAIT // 5.删除或注释掉这个宏, 进入下一个练习(项目正式代码练习) + d2x::wait(); // 5.删除或注释掉这一行, 进入下一个练习(项目正式代码练习) return 0; } @@ -125,23 +147,23 @@ int main() { **控制台输出及解释** ```bash -🌏Progress: [>----------] 0/10 -->> 显示当前的练习进度 +🌏Progress: [>----------] 0/52 -->> 显示当前的练习进度 -[Target: 00-0-hello-mcpp] - normal -->> 当前的练习名 +[Exercise: hello-mcpp] -->> 当前的练习名 -❌ Error: Compilation/Running failed for dslings/hello-mcpp.cpp -->> 显示检测状态 +❌ Error: Compilation/Running failed for src/intro/tests/hello-mcpp.cpp -->> 显示检测状态 The code exist some error! ----------C-Output--------- - 编译器输出信息 -[HONLY LOGW]: main: dslings/hello-mcpp.cpp:24 - ❌ | a == 1.1 (1 == 1.100000) -->> 错误提示及位置(24行) -[HONLY LOGW]: main: dslings/hello-mcpp.cpp:26 - 🥳 Delete the D2X_WAIT to continue... +---------Output--------- - 编译/运行输出信息 +❌ | a == 1.1 (1 == 1.1) --> src/intro/tests/hello-mcpp.cpp:41 -->> 错误提示及位置(41行) +🚧 | Delete the d2x::wait() to continue --> src/intro/tests/hello-mcpp.cpp:47 AI-Tips-Config: https://xlings.d2learn.org/documents/d2x/intro.html -->> AI提示(需要配置大模型的key, 可不使用) ---------E-Files--------- -dslings/hello-mcpp.cpp -->> 当前检测的文件 +src/intro/tests/hello-mcpp.cpp -->> 当前检测的文件 ------------------------- Homepage: https://github.com/openxlings/xlings @@ -156,7 +178,7 @@ Homepage: https://github.com/openxlings/xlings ```bash { "version": "0.1.1", - "buildtools": "xmake d2x-buildtools", + "buildtools": "mcpp run -q -p d2x/buildtools --", "lang": "en", < -- 修改这里 ... } @@ -166,17 +188,18 @@ Homepage: https://github.com/openxlings/xlings 如果你希望使用 Neovim 编辑器并获得 LSP(clangd)支持, 可以按如下步骤进行配置 -**1.编辑项目配置文件`config.xlings`中的`editor`属性, 设置为`nvim` (或`zed`)** +**1.编辑项目配置文件`.d2x.json`中的`editor`字段, 设置为`nvim` (或`zed`)** -```bash +```json { - "version": "0.1.1", - "buildtools": "xmake d2x-buildtools", - "lang": "en", < -- 修改这里 + "buildtools": "mcpp run -q -p d2x/buildtools --", + "editor": "nvim", ... } ``` +> 未配置时按 `$VISUAL` → `$EDITOR` → `code` 回退;支持 `{file}` 占位符;显式配空串表示关闭自动打开。 + **2.在项目根目录运行一键依赖安装和环境配置命令** ```bash diff --git a/book/src/cpp11/00-auto-and-decltype.md b/book/src/cpp11/00-auto-and-decltype.md index 50b8586..d6636f4 100644 --- a/book/src/cpp11/00-auto-and-decltype.md +++ b/book/src/cpp11/00-auto-and-decltype.md @@ -12,7 +12,7 @@ auto 和 decltype 是C++11引入的强有力的**类型自动推导**工具. 不 | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference-auto](https://en.cppreference.com/w/cpp/language/auto) / [cppreference-decltype](https://en.cppreference.com/w/cpp/language/decltype) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/00-auto-and-decltype.md) | [视频解读](https://www.bilibili.com/video/BV1EzJs6HEf7) / [练习讲解](https://www.bilibili.com/video/BV1xkdYYUEyH) | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/00-auto-and-decltype-0.cpp) | | +| [cppreference-auto](https://en.cppreference.com/w/cpp/language/auto) / [cppreference-decltype](https://en.cppreference.com/w/cpp/language/decltype) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/00-auto-and-decltype.md) | [视频解读](https://www.bilibili.com/video/BV1EzJs6HEf7) / [练习讲解](https://www.bilibili.com/video/BV1xkdYYUEyH) | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/00-auto-and-decltype/0.cpp) | | **为什么引入?** @@ -252,12 +252,12 @@ decltype( (b) ) // 推导结果是 int & ### 练习代码主题 -- 0 - [声明定义](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/00-auto-and-decltype-0.cpp) -- 1 - [表达式类型推导](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/00-auto-and-decltype-1.cpp) -- 2 - [复杂类型推导 - 迭代器 / 函数](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/00-auto-and-decltype-2.cpp) -- 3 - [函数返回值类型推导](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/00-auto-and-decltype-3.cpp) -- 4 - [类/结构体成员类型推导](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/00-auto-and-decltype-4.cpp) -- 5 - [const 与引用的剥离和保留](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/00-auto-and-decltype-5.cpp) +- 0 - [声明定义](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/00-auto-and-decltype/0.cpp) +- 1 - [表达式类型推导](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/00-auto-and-decltype/1.cpp) +- 2 - [复杂类型推导 - 迭代器 / 函数](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/00-auto-and-decltype/2.cpp) +- 3 - [函数返回值类型推导](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/00-auto-and-decltype/3.cpp) +- 4 - [类/结构体成员类型推导](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/00-auto-and-decltype/4.cpp) +- 5 - [const 与引用的剥离和保留](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/00-auto-and-decltype/5.cpp) ### 练习代码自动检测命令 diff --git a/book/src/cpp11/01-default-and-delete.md b/book/src/cpp11/01-default-and-delete.md index 57b1a31..0d92170 100644 --- a/book/src/cpp11/01-default-and-delete.md +++ b/book/src/cpp11/01-default-and-delete.md @@ -12,7 +12,7 @@ | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/function#Deleted_functions) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/01-default-and-delete.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/01-default-and-delete-0.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/function#Deleted_functions) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/01-default-and-delete.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/01-default-and-delete/0.cpp) | | **为什么引入?** @@ -217,9 +217,9 @@ only_int(1.0); // 错误: 调用 deleted function ### 练习代码主题 -- 0 - [显式指定构造函数生成行为](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/01-default-and-delete-0.cpp) -- 1 - [实现不可拷贝但可移动的 UniquePtr](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/01-default-and-delete-1.cpp) -- 2 - [用 = delete 屏蔽特定参数类型的重载](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/01-default-and-delete-2.cpp) +- 0 - [显式指定构造函数生成行为](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/01-default-and-delete/0.cpp) +- 1 - [实现不可拷贝但可移动的 UniquePtr](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/01-default-and-delete/1.cpp) +- 2 - [用 = delete 屏蔽特定参数类型的重载](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/01-default-and-delete/2.cpp) ### 练习代码自动检测命令 diff --git a/book/src/cpp11/02-final-and-override.md b/book/src/cpp11/02-final-and-override.md index fa40a7a..6049852 100644 --- a/book/src/cpp11/02-final-and-override.md +++ b/book/src/cpp11/02-final-and-override.md @@ -12,7 +12,7 @@ final 和 override 是 C++11 引入的两个 **上下文相关标识符**, 用 | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference-final](https://en.cppreference.com/w/cpp/language/final) / [cppreference-override](https://en.cppreference.com/w/cpp/language/override) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/02-final-and-override.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/02-final-and-override-0.cpp) | | +| [cppreference-final](https://en.cppreference.com/w/cpp/language/final) / [cppreference-override](https://en.cppreference.com/w/cpp/language/override) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/02-final-and-override.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/02-final-and-override/0.cpp) | | **为什么引入?** @@ -174,9 +174,9 @@ struct B : A { ### 练习代码主题 -- 0 - [熟悉 override 的使用](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/02-final-and-override-0.cpp) -- 1 - [熟悉 final 的使用](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/02-final-and-override-1.cpp) -- 2 - [final + 模板方法 - AudioPlayer / WAV / MP3 / OGG](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/02-final-and-override-2.cpp) +- 0 - [熟悉 override 的使用](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/02-final-and-override/0.cpp) +- 1 - [熟悉 final 的使用](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/02-final-and-override/1.cpp) +- 2 - [final + 模板方法 - AudioPlayer / WAV / MP3 / OGG](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/02-final-and-override/2.cpp) ### 练习代码自动检测命令 diff --git a/book/src/cpp11/03-trailing-return-type.md b/book/src/cpp11/03-trailing-return-type.md index 9fba383..042274e 100644 --- a/book/src/cpp11/03-trailing-return-type.md +++ b/book/src/cpp11/03-trailing-return-type.md @@ -12,7 +12,7 @@ | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/function) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/03-trailing-return-type.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/03-trailing-return-type.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/function) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/03-trailing-return-type.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/03-trailing-return-type/0.cpp) | | **为什么引入?** @@ -166,7 +166,7 @@ auto func() -> int(*)[3]; // ok: 返回数组指针 ### 练习代码主题 -- 0 - [熟悉尾置返回类型 - 普通函数 / 模板 / lambda 三种形态](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/03-trailing-return-type.cpp) +- 0 - [熟悉尾置返回类型 - 普通函数 / 模板 / lambda 三种形态](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/03-trailing-return-type/0.cpp) ### 练习代码自动检测命令 diff --git a/book/src/cpp11/04-rvalue-references.md b/book/src/cpp11/04-rvalue-references.md index 03d3b13..92a4b07 100644 --- a/book/src/cpp11/04-rvalue-references.md +++ b/book/src/cpp11/04-rvalue-references.md @@ -12,7 +12,7 @@ | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/reference) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/04-rvalue-references.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/04-rvalue-references.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/reference) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/04-rvalue-references.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/04-rvalue-references/0.cpp) | | **为什么引入?** @@ -156,7 +156,7 @@ template void h(T&&); // 万能引用, 左右值都接受 ### 练习代码主题 -- 0 - [使用右值引用延长临时对象生命周期并修改其值](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/04-rvalue-references.cpp) +- 0 - [使用右值引用延长临时对象生命周期并修改其值](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/04-rvalue-references/0.cpp) ### 练习代码自动检测命令 diff --git a/book/src/cpp11/05-move-semantics.md b/book/src/cpp11/05-move-semantics.md index 6f18793..f0adf59 100644 --- a/book/src/cpp11/05-move-semantics.md +++ b/book/src/cpp11/05-move-semantics.md @@ -12,7 +12,7 @@ | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference-move](https://en.cppreference.com/w/cpp/utility/move) / [cppreference-move-ctor](https://en.cppreference.com/w/cpp/language/move_constructor) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/05-move-semantics.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/05-move-semantics-0.cpp) | | +| [cppreference-move](https://en.cppreference.com/w/cpp/utility/move) / [cppreference-move-ctor](https://en.cppreference.com/w/cpp/language/move_constructor) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/05-move-semantics.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/05-move-semantics/0.cpp) | | **为什么引入?** @@ -187,9 +187,9 @@ Buffer bad() { ### 练习代码主题 -- 0 - [移动构造与触发时机 - 让 buff 传递只做一次资源分配](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/05-move-semantics-0.cpp) -- 1 - [移动赋值与触发时机 - 临时对象 / 中间对象 / 显式 std::move 三种场景](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/05-move-semantics-1.cpp) -- 2 - [移动的是资源而不是对象 - 对比对象地址和 data 指针](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/05-move-semantics-2.cpp) +- 0 - [移动构造与触发时机 - 让 buff 传递只做一次资源分配](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/05-move-semantics/0.cpp) +- 1 - [移动赋值与触发时机 - 临时对象 / 中间对象 / 显式 std::move 三种场景](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/05-move-semantics/1.cpp) +- 2 - [移动的是资源而不是对象 - 对比对象地址和 data 指针](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/05-move-semantics/2.cpp) ### 练习代码自动检测命令 diff --git a/book/src/cpp11/06-scoped-enums.md b/book/src/cpp11/06-scoped-enums.md index 99c9066..193fe40 100644 --- a/book/src/cpp11/06-scoped-enums.md +++ b/book/src/cpp11/06-scoped-enums.md @@ -12,7 +12,7 @@ scoped enum (`enum class` / `enum struct`) 是 C++11 引入的强类型枚举, | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/enum) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/06-scoped-enums.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/06-scoped-enums-0.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/enum) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/06-scoped-enums.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/06-scoped-enums/0.cpp) | | **为什么引入?** @@ -204,8 +204,8 @@ constexpr Perm operator|(Perm a, Perm b) { ### 练习代码主题 -- 0 - [传统 enum 的潜在问题 - 名字冲突与隐式比较](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/06-scoped-enums-0.cpp) -- 1 - [scoped enum 基本用法 - 作用域 / 类型安全 / 底层类型](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/06-scoped-enums-1.cpp) +- 0 - [传统 enum 的潜在问题 - 名字冲突与隐式比较](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/06-scoped-enums/0.cpp) +- 1 - [scoped enum 基本用法 - 作用域 / 类型安全 / 底层类型](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/06-scoped-enums/1.cpp) ### 练习代码自动检测命令 diff --git a/book/src/cpp11/07-constexpr.md b/book/src/cpp11/07-constexpr.md index beee2e8..ea6a3da 100644 --- a/book/src/cpp11/07-constexpr.md +++ b/book/src/cpp11/07-constexpr.md @@ -12,7 +12,7 @@ constexpr 是 C++11 引入的关键字, 用于把"原本要等到运行期才能 | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/constexpr) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/07-constexpr.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/07-constexpr-0.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/constexpr) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/07-constexpr.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/07-constexpr/0.cpp) | | **为什么引入?** @@ -181,8 +181,8 @@ constexpr 把计算搬到编译期, 也意味着错误诊断、调试栈信息 ### 练习代码主题 -- 0 - [编译期计算基础: constexpr 和 const 的区别](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/07-constexpr-0.cpp) -- 1 - [编译期计算应用示例: factorial / Sum / mysin 自动打表](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/07-constexpr-1.cpp) +- 0 - [编译期计算基础: constexpr 和 const 的区别](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/07-constexpr/0.cpp) +- 1 - [编译期计算应用示例: factorial / Sum / mysin 自动打表](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/07-constexpr/1.cpp) ### 练习代码自动检测命令 diff --git a/book/src/cpp11/08-literal-type.md b/book/src/cpp11/08-literal-type.md index d7da3ba..8cba86c 100644 --- a/book/src/cpp11/08-literal-type.md +++ b/book/src/cpp11/08-literal-type.md @@ -12,7 +12,7 @@ | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference-LiteralType](https://en.cppreference.com/w/cpp/named_req/LiteralType) / [cppreference-user-literal](https://en.cppreference.com/w/cpp/language/user_literal) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/08-literal-type.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/08-literal-type-0.cpp) | | +| [cppreference-LiteralType](https://en.cppreference.com/w/cpp/named_req/LiteralType) / [cppreference-user-literal](https://en.cppreference.com/w/cpp/language/user_literal) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/08-literal-type.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/08-literal-type/0.cpp) | | **为什么引入?** @@ -178,8 +178,8 @@ LiteralType 要求至少有一个 **不是拷贝 / 移动** 的 constexpr 构造 ### 练习代码主题 -- 0 - [理解字面值类型的概念 - 哪些能 constexpr](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/08-literal-type-0.cpp) -- 1 - [自定义字面值类型 - 给 Vector 加 constexpr 构造](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/08-literal-type-1.cpp) +- 0 - [理解字面值类型的概念 - 哪些能 constexpr](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/08-literal-type/0.cpp) +- 1 - [自定义字面值类型 - 给 Vector 加 constexpr 构造](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/08-literal-type/1.cpp) ### 练习代码自动检测命令 diff --git a/book/src/cpp11/09-list-initialization.md b/book/src/cpp11/09-list-initialization.md index 0ec452c..ea54703 100644 --- a/book/src/cpp11/09-list-initialization.md +++ b/book/src/cpp11/09-list-initialization.md @@ -12,7 +12,7 @@ | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/list_initialization.html) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/09-list-initialization.md) | [视频解读](https://www.bilibili.com/video/BV1vKuQzkEo2) | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/09-list-initialization-0.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/list_initialization.html) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/09-list-initialization.md) | [视频解读](https://www.bilibili.com/video/BV1vKuQzkEo2) | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/09-list-initialization/0.cpp) | | **为什么引入?** diff --git a/book/src/cpp11/10-delegating-constructors.md b/book/src/cpp11/10-delegating-constructors.md index e4cb719..e52e2c9 100644 --- a/book/src/cpp11/10-delegating-constructors.md +++ b/book/src/cpp11/10-delegating-constructors.md @@ -12,7 +12,7 @@ | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/initializer_list.html#Delegating_constructor) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/10-delegating-constructors.md) | [视频解读](https://www.bilibili.com/video/BV1zft3zSEER) | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/10-delegating-constructors-0.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/initializer_list.html#Delegating_constructor) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/10-delegating-constructors.md) | [视频解读](https://www.bilibili.com/video/BV1zft3zSEER) | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/10-delegating-constructors/0.cpp) | | **为什么引入?** diff --git a/book/src/cpp11/11-inherited-constructors.md b/book/src/cpp11/11-inherited-constructors.md index 303e65a..0784c4a 100644 --- a/book/src/cpp11/11-inherited-constructors.md +++ b/book/src/cpp11/11-inherited-constructors.md @@ -12,7 +12,7 @@ | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/using_declaration.html#Inheriting_constructors) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/11-inherited-constructors.md) | [Bili](https://www.bilibili.com/video/BV1bspBzFEEC) / [Youtube](https://youtu.be/p7vbY8XUKnY?si=GZUn9GSW68aU94A6) | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/11-inherited-constructors-0.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/using_declaration.html#Inheriting_constructors) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/11-inherited-constructors.md) | [Bili](https://www.bilibili.com/video/BV1bspBzFEEC) / [Youtube](https://youtu.be/p7vbY8XUKnY?si=GZUn9GSW68aU94A6) | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/11-inherited-constructors/0.cpp) | | **为什么引入?** @@ -224,9 +224,9 @@ auto p4 = p2; // error (不能拷贝) ### 练习代码主题 -- 0 - [熟悉继承构造函数特性](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/11-inherited-constructors-0.cpp) -- 1 - [在功能扩展中的应用 - StudentTest](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/11-inherited-constructors-1.cpp) -- 2 - [在泛型模板中的应用 - NoCopy / NoMove 行为约束](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/11-inherited-constructors-2.cpp) +- 0 - [熟悉继承构造函数特性](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/11-inherited-constructors/0.cpp) +- 1 - [在功能扩展中的应用 - StudentTest](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/11-inherited-constructors/1.cpp) +- 2 - [在泛型模板中的应用 - NoCopy / NoMove 行为约束](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/11-inherited-constructors/2.cpp) ### 练习代码自动检测命令 diff --git a/book/src/cpp11/12-nullptr.md b/book/src/cpp11/12-nullptr.md index 4827e5e..3fa767f 100644 --- a/book/src/cpp11/12-nullptr.md +++ b/book/src/cpp11/12-nullptr.md @@ -12,7 +12,7 @@ | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/nullptr) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/12-nullptr.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/12-nullptr-0.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/nullptr) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/12-nullptr.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/12-nullptr/0.cpp) | | **为什么引入?** @@ -193,9 +193,9 @@ bool isEmpty = (ptr == nullptr); // true ### 练习代码主题 -- 0 - [nullptr基础用法](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/12-nullptr-0.cpp) -- 1 - [nullptr的函数重载](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/12-nullptr-1.cpp) -- 2 - [nullptr在模板编程中的优势](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/12-nullptr-2.cpp) +- 0 - [nullptr基础用法](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/12-nullptr/0.cpp) +- 1 - [nullptr的函数重载](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/12-nullptr/1.cpp) +- 2 - [nullptr在模板编程中的优势](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/12-nullptr/2.cpp) ### 练习代码自动检测命令 diff --git a/book/src/cpp11/13-long-long.md b/book/src/cpp11/13-long-long.md index cf47687..2ed5b68 100644 --- a/book/src/cpp11/13-long-long.md +++ b/book/src/cpp11/13-long-long.md @@ -12,7 +12,7 @@ | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/types) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/13-long-long.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/13-long-long-0.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/types) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/13-long-long.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/13-long-long/0.cpp) | | **为什么引入?** @@ -109,8 +109,8 @@ if (bigValue > std::numeric_limits::max() || bigValue < std::numeric_limits ### 练习代码主题 -- 0 - [long long基础用法](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/13-long-long-0.cpp) -- 1 - [long long大数应用和边界值](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/13-long-long-1.cpp) +- 0 - [long long基础用法](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/13-long-long/0.cpp) +- 1 - [long long大数应用和边界值](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/13-long-long/1.cpp) ### 练习代码自动检测命令 diff --git a/book/src/cpp11/14-type-alias.md b/book/src/cpp11/14-type-alias.md index 5a78af6..745fcd9 100644 --- a/book/src/cpp11/14-type-alias.md +++ b/book/src/cpp11/14-type-alias.md @@ -12,7 +12,7 @@ | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference-type-alias](https://en.cppreference.com/w/cpp/language/type_alias) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/14-type-alias.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/14-type-alias-0.cpp) | | +| [cppreference-type-alias](https://en.cppreference.com/w/cpp/language/type_alias) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/14-type-alias.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/14-type-alias/0.cpp) | | > 注: `using`关键字在C++11之前就已经存在, 但当时主要是作为命名空间和类成员声明来使用的 > - 声明命名空间: `using namespace std;` @@ -192,10 +192,10 @@ struct A { ### 练习代码主题 -- 0 - [基本类型别名](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/14-type-alias-0.cpp) -- 1 - [复杂类型和函数指针别名](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/14-type-alias-1.cpp) -- 2 - [别名模板基础](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/14-type-alias-2.cpp) -- 3 - [标准库中的别名模板应用](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/14-type-alias-3.cpp) +- 0 - [基本类型别名](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/14-type-alias/0.cpp) +- 1 - [复杂类型和函数指针别名](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/14-type-alias/1.cpp) +- 2 - [别名模板基础](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/14-type-alias/2.cpp) +- 3 - [标准库中的别名模板应用](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/14-type-alias/3.cpp) ### 练习代码自动检测命令 diff --git a/book/src/cpp11/15-variadic-templates.md b/book/src/cpp11/15-variadic-templates.md index 9a259db..8a3a646 100644 --- a/book/src/cpp11/15-variadic-templates.md +++ b/book/src/cpp11/15-variadic-templates.md @@ -12,7 +12,7 @@ | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference](https://en.cppreference.com/w/cpp/language/parameter_pack) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/15-variadic-templates.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/15-variadic-templates-0.cpp) | | +| [cppreference](https://en.cppreference.com/w/cpp/language/parameter_pack) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/15-variadic-templates.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/15-variadic-templates/0.cpp) | | **为什么引入?** @@ -228,8 +228,8 @@ auto save(Args&&... args) { ### 练习代码主题 -- 0 - [可变参数模板基础 - 递归展开 print](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/15-variadic-templates-0.cpp) -- 1 - [可变参数模板求和 - sum](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/15-variadic-templates-1.cpp) +- 0 - [可变参数模板基础 - 递归展开 print](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/15-variadic-templates/0.cpp) +- 1 - [可变参数模板求和 - sum](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/15-variadic-templates/1.cpp) ### 练习代码自动检测命令 diff --git a/book/src/cpp11/16-generalized-unions.md b/book/src/cpp11/16-generalized-unions.md index 3934262..d098a4d 100644 --- a/book/src/cpp11/16-generalized-unions.md +++ b/book/src/cpp11/16-generalized-unions.md @@ -14,7 +14,7 @@ | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference-union](https://cppreference.com/w/cpp/language/union.html) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/16-generalized-unions.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/16-generalized-unions-0.cpp) | | +| [cppreference-union](https://cppreference.com/w/cpp/language/union.html) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/16-generalized-unions.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/16-generalized-unions/0.cpp) | | **为什么引入** @@ -222,9 +222,9 @@ double c = m.b; // 错误:未定义行为 ### 练习代码主题 -- 0 - [联合体默认成员初始化 - 最多一个变体成员可带默认初始化器](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/16-generalized-unions-0.cpp) -- 1 - [联合体包含非平凡类型及生命周期管理 - placement new 构造 / 显式析构](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/16-generalized-unions-1.cpp) -- 2 - [带标签的鉴别联合体 - 用 enum + union 实现简易 variant](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/16-generalized-unions-2.cpp) +- 0 - [联合体默认成员初始化 - 最多一个变体成员可带默认初始化器](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/16-generalized-unions/0.cpp) +- 1 - [联合体包含非平凡类型及生命周期管理 - placement new 构造 / 显式析构](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/16-generalized-unions/1.cpp) +- 2 - [带标签的鉴别联合体 - 用 enum + union 实现简易 variant](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/16-generalized-unions/2.cpp) ### 练习代码自动检测命令 diff --git a/book/src/cpp11/17-pod-type.md b/book/src/cpp11/17-pod-type.md index 79732dc..8ffc389 100644 --- a/book/src/cpp11/17-pod-type.md +++ b/book/src/cpp11/17-pod-type.md @@ -13,7 +13,7 @@ C++ 早期标准为了描述这类“行为上接近 C struct 的类型”,引 | 书籍 | 视频 | 代码 | 交流 | | --- | --- | --- | --- | -| [cppreference-PODType](https://cppreference.com/w/cpp/named_req/PODType.html) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/17-pod-type.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/17-pod-type-0.cpp) | [论坛讨论](https://forum.d2learn.org/category/20) | +| [cppreference-PODType](https://cppreference.com/w/cpp/named_req/PODType.html) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/17-pod-type.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/17-pod-type/0.cpp) | [论坛讨论](https://forum.d2learn.org/category/20) | > 注意:从 C++20 开始,标准中的 “PODType” 概念已被标记为**弃用**。标准库更倾向于使用更细化的类别,如 `TrivialType`、`StandardLayoutType`、`ScalarType` 等来描述相关需求。 @@ -140,9 +140,9 @@ void pod_only_copy(const T& src, T& dst) { ### 练习代码主题 -- 0 - [使用类型特征判断 POD / trivial / standard layout](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/17-pod-type-0.cpp) -- 1 - [模拟按字节拷贝 POD 结构体,体会其行为](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/17-pod-type-1.cpp) -- 2 - [为 C 接口传入合适的 POD 类型数据](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/17-pod-type-2.cpp) +- 0 - [使用类型特征判断 POD / trivial / standard layout](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/17-pod-type/0.cpp) +- 1 - [模拟按字节拷贝 POD 结构体,体会其行为](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/17-pod-type/1.cpp) +- 2 - [为 C 接口传入合适的 POD 类型数据](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp11/tests/17-pod-type/2.cpp) ### 练习代码自动检测命令 diff --git a/book/src/cpp14/00-generic-lambdas.md b/book/src/cpp14/00-generic-lambdas.md index 892b39c..a2a8d9d 100644 --- a/book/src/cpp14/00-generic-lambdas.md +++ b/book/src/cpp14/00-generic-lambdas.md @@ -12,7 +12,7 @@ | Book | Video | Code | X | | --- | --- | --- | --- | -| [cppreference-lambda](https://en.cppreference.com/w/cpp/language/lambda) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp14/00-generic-lambdas.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp14/00-generic-lambdas-0.cpp) | | +| [cppreference-lambda](https://en.cppreference.com/w/cpp/language/lambda) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp14/00-generic-lambdas.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp14/tests/00-generic-lambdas/0.cpp) | | **为什么引入?** @@ -191,8 +191,8 @@ C++14 的泛型 lambda 支持参数包 — `[](auto... xs)` 可以接受任意 ### 练习代码主题 -- 0 - [泛型 lambda 基础 — auto 参数与类型推导](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp14/00-generic-lambdas-0.cpp) -- 1 - [泛型 lambda 与 STL 算法 — 排序、查找、函数工厂](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp14/00-generic-lambdas-1.cpp) +- 0 - [泛型 lambda 基础 — auto 参数与类型推导](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp14/tests/00-generic-lambdas/0.cpp) +- 1 - [泛型 lambda 与 STL 算法 — 排序、查找、函数工厂](https://github.com/mcpp-community/d2mcpp/blob/main/src/cpp14/tests/00-generic-lambdas/1.cpp) ### 练习代码自动检测命令 diff --git a/d2x/buildtools/README.md b/d2x/buildtools/README.md deleted file mode 100644 index 9106a16..0000000 --- a/d2x/buildtools/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# d2x 支持的构建工具 - -通过对构建工具做最小化的接口规范来适配不同编程语言及其工具链 - -## 构建工具接口规范 - -``` -xxx d2x-buildtools [command] [target] - -Commands: - list List all targets - build Build specified target - run Run specified target -``` \ No newline at end of file diff --git a/d2x/buildtools/cmake/README.md b/d2x/buildtools/cmake/README.md deleted file mode 100644 index 30404ce..0000000 --- a/d2x/buildtools/cmake/README.md +++ /dev/null @@ -1 +0,0 @@ -TODO \ No newline at end of file diff --git a/d2x/buildtools/mcpp.toml b/d2x/buildtools/mcpp.toml new file mode 100644 index 0000000..d271559 --- /dev/null +++ b/d2x/buildtools/mcpp.toml @@ -0,0 +1,6 @@ +[package] +name = "d2x-buildtools" +version = "0.1.0" +description = "d2mcpp 的 d2x Provider:枚举练习、生成 mcpp 清单、构建/运行/判定" +license = "Apache-2.0" +standard = "c++26" diff --git a/d2x/buildtools/src/discovery.cppm b/d2x/buildtools/src/discovery.cppm new file mode 100644 index 0000000..9f530fd --- /dev/null +++ b/d2x/buildtools/src/discovery.cppm @@ -0,0 +1,179 @@ +// 练习发现:目录约定,别无其他。 +// +// 刻意不引入独立的声明文件(exercises.toml 之类)。rustlings 最贵的一课 +// 是 PR #1355:edition 同时写在 rustc 参数和 rust-project.json 里,两边漂移 +// 酿成 bug。任何独立声明文件都是第二套真相源。这里的真相只有一处,且 +// 无法漂移:目录结构本身。 +// +// src/intro/tests/hello-mcpp.cpp → id: hello-mcpp (chapter: intro) +// src/cpp11/tests/00-auto-and-decltype/0.cpp → id: cpp11-00-auto-and-decltype-0 +// src/en/cpp11/tests/... lang=en 时启用,与 zh 互斥 +// +// 每个 / 是真实 mcpp 工程,练习就是它的 tests/ —— 学习者可以绕过 d2x +// 直接 `mcpp test -p cpp11` 看进度表,Provider 走的是同一条路。 +module; + +#include // stderr + +export module d2x.provider.discovery; + +import std; + +namespace fs = std::filesystem; + +namespace d2x::discovery { + +export struct Exercise { + std::string id; // cpp11-00-auto-and-decltype-0(与旧布局完全一致,进度不丢) + int order{}; // 显式顺序,不依赖字典序 + std::string title; // auto and decltype (0) + std::string chapter; // cpp11/00-auto-and-decltype + std::string member; // workspace 成员:cpp11 / intro / en/cpp11 … + std::string test_name; // mcpp test 里的名字:00-auto-and-decltype/0 / hello-mcpp + fs::path file; // 绝对路径 +}; + +// .d2x.json 中此处只需读取 "lang"。引入完整 JSON 解析器并无必要, +// 但也不能假装解析——这里只做一件明确的事:取出 "lang" 的字符串值。 +export std::string read_lang(const fs::path& root) { + std::ifstream in(root / ".d2x.json"); + if (!in) return "en"; + std::string text((std::istreambuf_iterator(in)), {}); + + auto key = text.find("\"lang\""); + if (key == std::string::npos) return "en"; + auto colon = text.find(':', key); + if (colon == std::string::npos) return "en"; + auto open = text.find('"', colon); + if (open == std::string::npos) return "en"; + auto close = text.find('"', open + 1); + if (close == std::string::npos) return "en"; + return text.substr(open + 1, close - open - 1); +} + +// cpp11 -> 11。用于排序,让 cpp11 的练习永远排在 cpp14 之前。 +int std_rank(std::string_view dir) { + if (dir.starts_with("cpp")) { + int n = 0; + auto rest = dir.substr(3); + auto [_, ec] = std::from_chars(rest.data(), rest.data() + rest.size(), n); + if (ec == std::errc{}) return n; + } + return -1; // intro +} + +// 00-auto-and-decltype -> { chapter_no=0, topic="auto-and-decltype" } +struct ChapterParts { int chapter_no; std::string topic; }; + +std::optional parse_chapter(std::string_view dir_name) { + auto dash = dir_name.find('-'); + if (dash == std::string_view::npos) return std::nullopt; + + int chapter_no = 0; + auto head = dir_name.substr(0, dash); + if (std::from_chars(head.data(), head.data() + head.size(), chapter_no).ec != std::errc{}) + return std::nullopt; + return ChapterParts{chapter_no, std::string(dir_name.substr(dash + 1))}; +} + +std::string humanize(std::string_view topic) { + std::string out(topic); + std::ranges::replace(out, '-', ' '); + return out; +} + +// 练习 id 直接来自目录/文件名,而它有两个危险去向: +// 1. d2x 把它拼进一条 shell 命令(` check `) +// 2. 我们把 test 名拼进 `mcpp test ` 命令行 +// 带反引号、引号或换行的名字在任一处都可能越界。在发现阶段拒绝比在下游各自转义更可靠。 +export bool valid_id(std::string_view id) { + if (id.empty()) return false; + return std::ranges::all_of(id, [](unsigned char c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9') || c == '-' || c == '_' || c == '.'; + }); +} + +// test 名多允许一个 '/'(章节目录分隔符),其余同 id 白名单。 +export bool valid_test_name(std::string_view name) { + if (name.empty()) return false; + return std::ranges::all_of(name, [](unsigned char c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9') || c == '-' || c == '_' || c == '.' + || c == '/'; + }); +} + +// 扫描一个成员工程的 tests/。std_dir 是去掉 en/ 前缀后的标准名(intro 为空串)。 +void scan_member(const fs::path& repo_root, const std::string& member, + const std::string& std_dir, std::vector& out) { + auto tests = repo_root / member / "tests"; + if (!fs::is_directory(tests)) return; + + for (const auto& entry : fs::recursive_directory_iterator(tests)) { + if (!entry.is_regular_file() || entry.path().extension() != ".cpp") continue; + + auto rel = fs::relative(entry.path(), tests); + Exercise ex; + ex.file = fs::absolute(entry.path()).lexically_normal(); + ex.member = member; + ex.test_name = rel.parent_path().empty() + ? rel.stem().string() + : std::format("{}/{}", rel.parent_path().generic_string(), + rel.stem().string()); + + auto chapter_dir = rel.parent_path().filename().string(); + auto parts = chapter_dir.empty() ? std::nullopt : parse_chapter(chapter_dir); + if (parts) { + int index = 0; + auto stem = rel.stem().string(); + std::from_chars(stem.data(), stem.data() + stem.size(), index); + ex.id = std::format("{}-{}-{}", std_dir, chapter_dir, stem); + ex.chapter = std::format("{}/{}", std_dir, chapter_dir); + ex.title = std::format("{} ({})", humanize(parts->topic), index); + ex.order = std_rank(std_dir) * 100'000 + parts->chapter_no * 100 + index; + } else { + // intro 之类不带章节目录的练习(tests/hello-mcpp.cpp) + ex.id = rel.stem().string(); + ex.chapter = "intro"; + ex.title = humanize(rel.stem().string()); + ex.order = -100'000; + } + + // 拒绝而不是转义:这类名字是课程作者的笔误或恶意 PR, + // 静默接受只会把问题推到下游。 + if (!valid_id(ex.id) || !valid_test_name(ex.test_name)) { + std::println(stderr, + "d2x-buildtools-mcpp: 跳过 '{}' —— 练习 id/名字 只允许 [A-Za-z0-9._/-]", + ex.file.string()); + continue; + } + out.push_back(std::move(ex)); + } +} + +// 扫描全部练习。课程工程住在 src/ 下;lang=en 用 src/en/ 镜像。 +export std::vector scan(const fs::path& repo_root, std::string_view lang) { + std::string prefix = (lang == "en") ? "src/en/" : "src/"; + std::vector found; + + scan_member(repo_root, prefix + "intro", "", found); + + std::vector std_dirs; + auto base = (lang == "en") ? repo_root / "src" / "en" : repo_root / "src"; + if (fs::is_directory(base)) { + for (const auto& entry : fs::directory_iterator(base)) { + auto name = entry.path().filename().string(); + if (entry.is_directory() && name.starts_with("cpp") + && fs::is_directory(entry.path() / "tests")) + std_dirs.push_back(name); + } + } + std::ranges::sort(std_dirs); + for (const auto& d : std_dirs) scan_member(repo_root, prefix + d, d, found); + + std::ranges::sort(found, {}, &Exercise::order); + return found; +} + +} // namespace d2x::discovery diff --git a/d2x/buildtools/src/emit.cppm b/d2x/buildtools/src/emit.cppm new file mode 100644 index 0000000..4615ca5 --- /dev/null +++ b/d2x/buildtools/src/emit.cppm @@ -0,0 +1,110 @@ +// NDJSON 事件输出。 +// +// 协议要求每一行都是一个完整的 JSON 对象,解析不了的行由 d2x 忽略—— +// 这正好吞掉 `mcpp run` 的前导空行和可能混入的编译输出,所以这里不需要 +// 任何哨兵前缀。唯一的硬要求是:一个事件绝不能跨行。 +module; + +// stdout / fputs / fflush 是宏与 C 运行时符号,import std 不提供, +// 必须走全局模块片段。 +#include + +export module d2x.provider.emit; + +import std; + +namespace d2x::emit { + +// JSON 字符串转义。练习输出里有 ANSI 转义序列、换行、引号,必须全部处理, +// 否则一个彩色编译错误就能把整行 JSON 打碎。 +export std::string escape(std::string_view s) { + std::string out; + out.reserve(s.size() + s.size() / 8); + for (unsigned char c : s) { + switch (c) { + case '"': out += "\\\""; break; + case '\\': out += "\\\\"; break; + case '\n': out += "\\n"; break; + case '\r': out += "\\r"; break; + case '\t': out += "\\t"; break; + case '\b': out += "\\b"; break; + case '\f': out += "\\f"; break; + default: + // ANSI 的 ESC(0x1b) 落在这里,按  编码 + if (c < 0x20) out += std::format("\\u{:04x}", static_cast(c)); + else out += static_cast(c); + } + } + return out; +} + +export std::string str(std::string_view v) { + return std::format("\"{}\"", escape(v)); +} + +export std::string array(const std::vector& items) { + std::string out = "["; + for (std::size_t i = 0; i < items.size(); ++i) { + if (i) out += ","; + out += items[i]; + } + out += "]"; + return out; +} + +// 一行一个事件,立刻 flush——d2x 是逐行读的,缓冲会让「实时看到编译输出」失效。 +export void line(std::string_view json_object) { + std::fputs(std::string(json_object).c_str(), stdout); + std::fputc('\n', stdout); + std::fflush(stdout); +} + +export void describe(std::string_view name, int protocol) { + line(std::format(R"({{"event":"describe","protocol":{},"name":{}}})", + protocol, str(name))); +} + +export void exercise(std::string_view id, int order, std::string_view title, + std::string_view chapter, const std::vector& files) { + std::vector quoted; + quoted.reserve(files.size()); + for (const auto& f : files) quoted.push_back(str(f)); + + line(std::format(R"({{"event":"exercise","id":{},"order":{},"title":{},"chapter":{},"files":{}}})", + str(id), order, str(title), str(chapter), array(quoted))); +} + +export void stage(std::string_view name) { + line(std::format(R"({{"event":"stage","name":{}}})", str(name))); +} + +export void output(std::string_view chunk) { + if (chunk.empty()) return; + line(std::format(R"({{"event":"output","chunk":{}}})", str(chunk))); +} + +export void verdict(std::string_view outcome, std::string_view stage_name, int exit_code, + const std::vector& diagnostics = {}) { + line(std::format(R"({{"event":"verdict","outcome":{},"stage":{},"exit_code":{},"diagnostics":{}}})", + str(outcome), str(stage_name), exit_code, array(diagnostics))); +} + +// 一条失败的断言 → 一个 Diagnostic。d2x 的前端据此做行内高亮和跳转, +// 学习者不用在几十行输出里找是哪一条没过。 +export std::string diagnostic(std::string_view file, int line_no, + std::string_view expr, + std::string_view expected, std::string_view actual) { + auto message = expected.empty() && actual.empty() + ? std::format("断言未通过: {}", expr) + : std::format("断言未通过: {} —— 期望 {},实际 {}", expr, expected, actual); + + return std::format( + R"({{"file":{},"line":{},"col":0,"severity":"error","message":{}}})", + str(file), line_no, str(message)); +} + +export void error(std::string_view message) { + line(std::format(R"({{"event":"error","message":{}}})", str(message))); +} + +} // namespace d2x::emit diff --git a/d2x/buildtools/src/main.cpp b/d2x/buildtools/src/main.cpp new file mode 100644 index 0000000..6b9e229 --- /dev/null +++ b/d2x/buildtools/src/main.cpp @@ -0,0 +1,159 @@ +// d2mcpp 的 d2x Provider。 +// +// describe 自我描述 +// exercises 枚举练习(有序) +// check 验证一道练习 +// +// 全部输出为 NDJSON 事件流,一行一个事件。d2x 忽略解析不了的行, +// 所以 `mcpp run` 的前导空行之类的噪声不会破坏协议。 +// +// 练习即测试:check 就是一次 `mcpp test -p --message-format +// json`,编译/退出码事实来自 mcpp 的 JSON 记录,运行期语义(断言/路障) +// 来自 harness 的侧信道 v2 —— 学习者绕过 d2x 直接 `mcpp test -p cpp11` +// 走的是完全相同的链路,不存在平行路径。 +// +// 用法(由 .d2x.json 的 buildtools 字段驱动,从仓库根执行,无需 cd): +// mcpp run -q -p d2x/buildtools -- check cpp11-00-auto-and-decltype-0 + +import std; + +import d2x.provider.emit; +import d2x.provider.discovery; +import d2x.provider.runner; + +namespace fs = std::filesystem; + +namespace { + +constexpr int kProtocolVersion = 1; + +// 向上找到仓库根:认 .d2x.json + mcpp.toml 同时存在。 +// 不能依赖可执行文件位置——它在 target///bin/ 里,层数不固定。 +std::optional find_repo_root() { + auto dir = fs::current_path(); + for (int depth = 0; depth < 12; ++depth) { + if (fs::exists(dir / ".d2x.json") && fs::exists(dir / "mcpp.toml")) + return dir; + if (!dir.has_parent_path() || dir.parent_path() == dir) break; + dir = dir.parent_path(); + } + return std::nullopt; +} + +int cmd_describe() { + d2x::emit::describe("mcpp", kProtocolVersion); + return 0; +} + +int cmd_exercises(const fs::path& root) { + auto lang = d2x::discovery::read_lang(root); + auto all = d2x::discovery::scan(root, lang); + if (all.empty()) { + d2x::emit::error(std::format("no exercises found under {} (lang={})", + root.string(), lang)); + return 1; + } + + for (const auto& ex : all) { + std::vector files{ex.file.string()}; + d2x::emit::exercise(ex.id, ex.order, ex.title, ex.chapter, files); + } + return 0; +} + +// 侧信道里的 file 若是相对路径(编译器以工程目录为基准时),在协议边界 +// 还原成绝对 —— d2x 靠它开编辑器、监听文件变更。展示归展示,定位归定位。 +std::string to_abs(const fs::path& root, const std::string& member, + const std::string& file) { + if (file.empty() || fs::path(file).is_absolute()) return file; + return (root / member / file).lexically_normal().string(); +} + +int cmd_check(const fs::path& root, std::string_view id) { + auto lang = d2x::discovery::read_lang(root); + auto all = d2x::discovery::scan(root, lang); + + auto it = std::ranges::find(all, id, &d2x::discovery::Exercise::id); + if (it == all.end()) { + d2x::emit::error(std::format("unknown exercise: {}", id)); + return 1; + } + + // 侧信道放在 .d2x/ 下:学习者进度旁边,不污染工程目录。 + auto result_file = root / ".d2x" / "result.ndjson"; + + // 从仓库根 spawn(Provider 由 d2x 在仓库根启动,mcpp 自己解析 workspace) + std::error_code ec; + fs::current_path(root, ec); + + d2x::emit::stage("compile"); + auto res = d2x::runner::run_mcpp_test(it->member, it->test_name, result_file); + + if (!res.package_error.empty()) { + // 包级构建失败:harness 或工程本身坏了 —— 这是课程基础设施问题, + // 不是这道题没做对。按协议约定不发 verdict(d2x 视为异常并原样呈现)。 + d2x::emit::output(res.package_error); + d2x::emit::error("课程构建失败(不是这道练习的问题)——请向课程仓库反馈"); + return 1; + } + if (!res.record) { + d2x::emit::error(std::format( + "mcpp test 没有返回 '{}' 的记录{}", it->test_name, + res.saw_any ? "" : "(mcpp 可能不支持 --message-format json,需要 >= 0.0.104)")); + return 1; + } + + const auto& rec = *res.record; + d2x::emit::output(rec.compile_output); + if (rec.status == "compile_fail") { + d2x::emit::verdict("fail", "compile", rec.exit_code); + return 0; // 练习没通过是正常业务路径,不是 Provider 出错 + } + + d2x::emit::stage("run"); + d2x::emit::output(rec.run_output); + + auto report = d2x::runner::judge_run(rec.exit_code, result_file); + + std::vector diags; + for (const auto& f : report.failures) { + diags.push_back(d2x::emit::diagnostic(to_abs(root, it->member, f.file), + f.line, f.what, f.expected, f.actual)); + } + + d2x::emit::verdict(d2x::runner::to_string(report.outcome), "run", + rec.exit_code, diags); + return 0; +} + +} // namespace + +int main(int argc, char** argv) { + std::vector args(argv + 1, argv + argc); + + if (args.empty()) { + d2x::emit::error("usage: describe | exercises | check "); + return 2; + } + + if (args[0] == "describe") return cmd_describe(); + + auto root = find_repo_root(); + if (!root) { + d2x::emit::error("repo root not found (looking for .d2x.json + mcpp.toml)"); + return 2; + } + + if (args[0] == "exercises") return cmd_exercises(*root); + + if (args[0] == "check") { + if (args.size() < 2) { + d2x::emit::error("check requires an exercise id"); + return 2; + } + return cmd_check(*root, args[1]); + } + + d2x::emit::error(std::format("unknown command: {}", args[0])); + return 2; +} diff --git a/d2x/buildtools/src/runner.cppm b/d2x/buildtools/src/runner.cppm new file mode 100644 index 0000000..1af14f7 --- /dev/null +++ b/d2x/buildtools/src/runner.cppm @@ -0,0 +1,234 @@ +// 调 `mcpp test --message-format json` 验证单个练习,并合并侧信道判定。 +// +// 这一层不再生成任何清单、不再自己算退出码语义 —— 编译/运行的事实由 +// mcpp 的 JSON 记录提供(status/exit_code/compile_output/run_output), +// 运行期语义(哪条断言挂了、路障拆没拆)由 harness 的侧信道 v2 提供, +// 两个来源在这里合并成 Provider 协议的 verdict。 +module; + +#include +#ifndef _WIN32 +# include +#endif +#include // setenv / _putenv_s + +export module d2x.provider.runner; + +import std; + +namespace fs = std::filesystem; + +namespace d2x::runner { + +export struct Captured { + int exit_code{}; + std::string output; +}; + +// 只要 stdout:JSON 协议流在 stdout,stderr 的人读错误信息这里不需要 +// (包级失败在 stdout 也有 {"error":"package"} 记录)。 +// +// 注:旧实现这里要先 unsetenv("LD_LIBRARY_PATH") 绕嵌套 mcpp 的 glibc +// 段错误 —— mcpp 已在上游根治(merged_environ 剥离私有 glibc 条目), +// workaround 随之删除。 +export Captured capture_stdout(const std::string& cmd) { + Captured result; + std::string full = cmd + " 2>/dev/null"; + +#ifdef _WIN32 + FILE* pipe = ::_popen(full.c_str(), "r"); +#else + FILE* pipe = ::popen(full.c_str(), "r"); +#endif + if (!pipe) return {127, std::format("failed to spawn: {}", cmd)}; + + char buf[4096]; + while (std::fgets(buf, sizeof(buf), pipe)) result.output += buf; + +#ifdef _WIN32 + int status = ::_pclose(pipe); + result.exit_code = status; +#else + int status = ::pclose(pipe); + // pclose 回的是 wait status,转成真实退出码,否则 exit 1 会变成 256 + result.exit_code = (status == -1) ? 127 + : WIFEXITED(status) ? WEXITSTATUS(status) + : WIFSIGNALED(status) ? 128 + WTERMSIG(status) + : status; +#endif + return result; +} + +// mcpp 的一条 per-test JSON 记录(我们关心的子集)。 +export struct TestRecord { + std::string test; // 相对 tests/ 的路径名,如 00-auto-and-decltype/0 + std::string status; // pass | compile_fail | run_fail + int exit_code{}; + std::string compile_output; + std::string run_output; +}; + +export struct McppTestResult { + std::optional record; // 精确匹配 test 名的那条 + std::string package_error; // {"error":"package"} 的 compile_output + bool saw_any = false; +}; + +// 从一行 JSON 里取字段。格式由 mcpp --message-format json 产出: +// 字段固定、无嵌套对象(summary 行不取),不引入 JSON 库。 +std::string field(std::string_view line, std::string_view key) { + auto pat = std::format("\"{}\":", key); + auto at = line.find(pat); + if (at == std::string_view::npos) return {}; + at += pat.size(); + if (at >= line.size()) return {}; + + if (line[at] == '"') { // 字符串值 + ++at; + std::string out; + while (at < line.size() && line[at] != '"') { + if (line[at] == '\\' && at + 1 < line.size()) { + ++at; + switch (line[at]) { + case 'n': out += '\n'; break; + case 't': out += '\t'; break; + case 'r': out += '\r'; break; + case 'u': { // \u00XX —— mcpp 只对 <0x20 编码 + if (at + 4 < line.size()) { + int v = 0; + auto hex = line.substr(at + 1, 4); + std::from_chars(hex.data(), hex.data() + 4, v, 16); + out += static_cast(v); + at += 4; + } + break; + } + default: out += line[at]; + } + } else { + out += line[at]; + } + ++at; + } + return out; + } + auto end = line.find_first_of(",}", at); // 裸值(数字/布尔/null) + return std::string(line.substr(at, end == std::string_view::npos ? end : end - at)); +} + +// 跑 `mcpp test` 并抽出目标测试的记录。pattern 是子串匹配,可能带出 +// 邻居测试(如 …/1 匹配 …/10),所以逐行解析后按 test 名精确挑。 +export McppTestResult run_mcpp_test(const std::string& member, + const std::string& test_name, + const fs::path& result_file) { + std::error_code ec; + fs::remove(result_file, ec); // harness 是追加写的,清掉上一轮残留 + fs::create_directories(result_file.parent_path(), ec); +#ifndef _WIN32 + ::setenv("D2X_RESULT_FILE", result_file.string().c_str(), 1); +#else + ::_putenv_s("D2X_RESULT_FILE", result_file.string().c_str()); +#endif + + auto cmd = std::format("mcpp test -q -p {} {} --message-format json", + member, test_name); + auto cap = capture_stdout(cmd); + + McppTestResult out; + std::istringstream lines(cap.output); + for (std::string line; std::getline(lines, line); ) { + if (line.empty() || line.front() != '{') continue; + if (line.find("\"error\":\"package\"") != std::string::npos) { + out.package_error = field(line, "compile_output"); + out.saw_any = true; + continue; + } + auto name = field(line, "test"); + if (name.empty()) continue; // summary 行等 + out.saw_any = true; + if (name != test_name) continue; + TestRecord rec; + rec.test = name; + rec.status = field(line, "status"); + rec.compile_output = field(line, "compile_output"); + rec.run_output = field(line, "run_output"); + auto raw = field(line, "exit_code"); + std::from_chars(raw.data(), raw.data() + raw.size(), rec.exit_code); + out.record = std::move(rec); + } + return out; +} + +// —— 侧信道判定(语义与设计稿 §5 的顺序表一致)—— + +export enum class Outcome { Pass, Fail, Blocked }; + +export std::string_view to_string(Outcome o) { + switch (o) { + case Outcome::Pass: return "pass"; + case Outcome::Fail: return "fail"; + case Outcome::Blocked: return "blocked"; + } + return "fail"; +} + +export struct Failure { + std::string what; + std::string expected; + std::string actual; + std::string file; + int line{}; +}; + +export struct RunReport { + Outcome outcome{Outcome::Pass}; + std::vector failures; +}; + +// 判定顺序(与代码一致;wait 必须先于退出码判定——d2x 库在存在未拆除的 +// wait 时会将退出码置为 1,若先判退出码,blocked 会被整体误判为 fail): +// 有 ok:false → Fail,每条失败都能转成一个 Diagnostic +// 无失败、有 wait → Blocked(答案已对,只差拆路障) +// 无失败但退出码非 0 → Fail(纯崩溃 / 练习自己 return 非 0) +// 侧信道文件不存在 → 退回「退出码为 0 即通过」 +// +// 最后一条让 harness 自动变成可选的:纯观察型练习可以是零依赖的 +// 纯 C++ 文件,学习者能原样拷进 Compiler Explorer。 +export RunReport judge_run(int exit_code, const fs::path& result_file) { + RunReport report; + + std::ifstream in(result_file); + if (!in) { + report.outcome = (exit_code == 0) ? Outcome::Pass : Outcome::Fail; + return report; + } + + bool saw_wait = false; + for (std::string line; std::getline(in, line); ) { + auto kind = field(line, "kind"); + if (kind == "wait") { saw_wait = true; continue; } + if (kind != "assert") continue; + if (field(line, "ok") == "true") continue; + + int line_no = 0; + auto raw = field(line, "line"); + std::from_chars(raw.data(), raw.data() + raw.size(), line_no); + + report.failures.push_back(Failure{ + .what = field(line, "what"), + .expected = field(line, "expected"), + .actual = field(line, "actual"), + .file = field(line, "file"), + .line = line_no, + }); + } + + if (!report.failures.empty()) report.outcome = Outcome::Fail; + else if (saw_wait) report.outcome = Outcome::Blocked; + else if (exit_code != 0) report.outcome = Outcome::Fail; + else report.outcome = Outcome::Pass; + + return report; +} + +} // namespace d2x::runner diff --git a/d2x/buildtools/tests/e2e.sh b/d2x/buildtools/tests/e2e.sh new file mode 100755 index 0000000..14f1c5a --- /dev/null +++ b/d2x/buildtools/tests/e2e.sh @@ -0,0 +1,118 @@ +#!/usr/bin/env bash +# d2mcpp 端到端验证 —— 两条硬断言,缺一不可: +# +# 1) 每个练习未完成时不通过 (pristine 全量 mcpp test 必须 0 passed) +# 2) 每份参考答案放进去后通过 (overlay 后全量 mcpp test 必须全绿) +# +# 这是 rustlings `cargo dev check --require-solutions` 的等价物。 +# +# 两道防线(均源自历史缺陷,背景见 .agents/docs 参考文档): +# - 脏树检查: 练习/答案目录有未提交改动时拒绝运行 —— 脚本要把答案覆盖到 +# 练习上再用 git 还原,未提交的改动会被覆盖丢失 +# - 防空转: overlay 后 passed 总数为 0 时直接失败,绝不静默绿灯 +# +# 用法: bash d2x/buildtools/tests/e2e.sh [zh|en|all] (默认 all) +# 依赖: PATH 里的 mcpp 需支持 mcpp test 逐测试隔离/过滤/--message-format json +set -uo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)" +cd "$ROOT" + +MODE="${1:-all}" + +run_lang() { + local prefix="$1" # "src/" (zh) 或 "src/en/" + local label="$2" + local members=("${prefix}intro" "${prefix}cpp11" "${prefix}cpp14") + local test_dirs=() + for m in "${members[@]}"; do test_dirs+=("$m/tests"); done + + # —— 防线 1: 脏树检查 —— + local dirty + dirty=$(git status --porcelain -- "${test_dirs[@]}" solutions/ | head -20) + if [[ -n "$dirty" ]]; then + echo "E2E($label) 拒绝运行: 练习/答案目录存在未提交改动(脚本的覆盖-还原流程会将其覆盖丢失):" + echo "$dirty" + return 1 + fi + + restore() { git checkout -q -- "${test_dirs[@]}"; } + + # —— 断言 1: pristine 全量必须 0 passed —— + local m out passed + for m in "${members[@]}"; do + out=$(mcpp test -p "$m" 2>&1) + passed=$(echo "$out" | grep -oE '[0-9]+ passed' | grep -oE '^[0-9]+' | tail -1) + if [[ "${passed:-0}" != "0" ]]; then + echo "E2E($label) FAIL: $m 在未完成状态下有 $passed 个练习通过了 —— 练习失去了「默认不通过」性质" + echo "$out" | grep " ... ok" | head -5 + return 1 + fi + done + echo "E2E($label) pristine: 全部练习保持未通过 ✓" + + # —— 覆盖参考答案 (zh/en 共用同一份 solutions) —— + local n_overlaid=0 sol rel std rest dst + while IFS= read -r sol; do + rel="${sol#solutions/}" # intro/hello-mcpp.cpp | cpp11/00-x/0.cpp + std="${rel%%/*}"; rest="${rel#*/}" + dst="${prefix}${std}/tests/${rest}" + if [[ ! -f "$dst" ]]; then + echo "E2E($label) FAIL: 答案 $sol 没有对应的练习文件 $dst" + restore + return 1 + fi + cp "$sol" "$dst" + n_overlaid=$((n_overlaid + 1)) + done < <(find solutions -name '*.cpp' | sort) + + # —— 断言 2 + 防线 2: overlay 后全绿,且 passed 总数与答案数一致 —— + local total_passed=0 ok=1 + for m in "${members[@]}"; do + out=$(mcpp test -p "$m" 2>&1) + if ! echo "$out" | grep -q "test result ok"; then + echo "E2E($label) FAIL: $m 覆盖答案后仍有失败:" + echo "$out" | grep -E "FAIL|failures" -A10 | head -15 + ok=0 + fi + passed=$(echo "$out" | grep -oE '[0-9]+ passed' | grep -oE '^[0-9]+' | tail -1) + total_passed=$((total_passed + ${passed:-0})) + done + restore + + if [[ "$ok" != 1 ]]; then return 1; fi + if [[ "$total_passed" -eq 0 ]]; then + echo "E2E($label) FAIL: 防空转 —— passed 总数为 0,脚本没有真正跑到任何练习" + return 1 + fi + if [[ "$total_passed" -ne "$n_overlaid" ]]; then + echo "E2E($label) FAIL: 覆盖了 $n_overlaid 份答案但只有 $total_passed 个练习通过" + return 1 + fi + echo "E2E($label) solutions: $total_passed/$n_overlaid 参考答案全部通过 ✓" +} + +provider_smoke() { + # Provider 协议冒烟:枚举数量、check 的关键事件 + local n + n=$(mcpp run -q -p d2x/buildtools -- exercises | grep -c '"event":"exercise"') + if [[ "$n" -lt 52 ]]; then + echo "E2E(provider) FAIL: 枚举到 $n 个练习(预期 >= 52)" + return 1 + fi + local out + out=$(mcpp run -q -p d2x/buildtools -- check hello-mcpp) + echo "$out" | grep -q '"event":"stage","name":"compile"' \ + && echo "$out" | grep -q '"event":"verdict"' \ + && echo "$out" | grep -q '"outcome":"fail"' \ + || { echo "E2E(provider) FAIL: check hello-mcpp 的事件流不完整:"; echo "$out" | head -3; return 1; } + echo "E2E(provider) 协议冒烟: $n 个练习,check 事件流完整 ✓" +} + +rc=0 +provider_smoke || rc=1 +if [[ "$MODE" == "zh" || "$MODE" == "all" ]]; then run_lang "src/" zh || rc=1; fi +if [[ "$MODE" == "en" || "$MODE" == "all" ]]; then run_lang "src/en/" en || rc=1; fi + +if [[ "$rc" == 0 ]]; then echo "E2E: ALL GREEN"; else echo "E2E: FAILED"; fi +exit "$rc" diff --git a/d2x/buildtools/xmake/main.lua b/d2x/buildtools/xmake/main.lua deleted file mode 100644 index b757d22..0000000 --- a/d2x/buildtools/xmake/main.lua +++ /dev/null @@ -1,67 +0,0 @@ -import("core.base.json") -import("core.base.option") -import("core.project.project") -import("core.project.config") - -local function get_d2x_lang() - local d2x_json_file = path.join(os.projectdir(), ".d2x.json") - if os.isfile(d2x_json_file) then - local d2x_config = json.loadfile(d2x_json_file) or {} - return d2x_config["lang"] - end - return nil -end - -function list() - - config.load() - local lang = get_d2x_lang() - if lang and #lang > 0 then - config.set("lang", lang, {force = true}) - end - - local targets = project.targets() - for name, _ in pairs(targets) do - local files = targets[name]:sourcefiles() - local flag = true - - -- cprintf / print xxx - printf(name) -- target name - for _, file in ipairs(files) do - file = path.absolute(file) - if flag then - --printf(": " .. file) -- avoid C:\ issue on Windows - printf("@ " .. file) - flag = false - else - printf(", " .. file) - end - end - printf("\n") - end -end - -function main() - - local command = option.get("command") - local target = option.get("target") - - os.cd(os.projectdir()) - --print("project file: " .. project.rootfile()) - - if command == "init" then - local lang = get_d2x_lang() - if lang and #lang > 0 then - os.exec("xmake f --lang=" .. lang) - end - elseif command == "list" then - list() - elseif command == "build" then - os.exec("xmake build " .. (target or "")) - elseif command == "run" then - os.exec("xmake run " .. (target or "")) - else - print("Unknown command: " .. tostring(command)) - end - -end diff --git a/d2x/buildtools/xmake/xmake.lua b/d2x/buildtools/xmake/xmake.lua deleted file mode 100644 index ad4a113..0000000 --- a/d2x/buildtools/xmake/xmake.lua +++ /dev/null @@ -1,14 +0,0 @@ -task("d2x-buildtools") - - set_category("plugin") - - on_run("main") - - set_menu { - usage = "xmake d2x-buildtools [options]", - description = "d2x buildtools plugin", - options = { - {nil, "command", "v", nil, "d2x-buildtools's command"}, - {nil, "target", "v", nil, "the target name"} - } - } \ No newline at end of file diff --git a/d2x/cpp/common.hpp b/d2x/cpp/common.hpp deleted file mode 100644 index c67d9df..0000000 --- a/d2x/cpp/common.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef COMMON_HPP_D2X -#define COMMON_HPP_D2X - -#include -#include - -#include - -#define d2x_assert(expr) \ -{ \ - if (!(expr)) { \ - HONLY_LOGW("❌(error) | %s", #expr); \ - } else { \ - HONLY_LOGI_P("✅ | %s", #expr); \ - } \ -} - -#define d2x_assert_eq(a, b) \ -{ \ - if (a != b) {\ - HONLY_LOGW("❌ | %s == %s (%s == %s)", \ - #a, #b, std::to_string(a).c_str(), std::to_string(b).c_str()); \ - } else {\ - HONLY_LOGI_P("✅ | %s == %s (%s == %s)", \ - #a, #b, std::to_string(a).c_str(), std::to_string(b).c_str()); \ - } \ -} - -#define D2X_WAIT HONLY_LOGW("🥳 Delete the D2X_WAIT to continue..."); -#define D2X_YOUR_ANSWER -#define D2X_DONT_DELETE_THIS(x) x - -template -class d2x_is_invocable { -private: - template - static auto test(U* f) -> decltype((*f)(std::declval()...), std::true_type()); - - template - static std::false_type test(...); - -public: - static constexpr bool value = decltype(test(nullptr))::value; -}; - -#endif \ No newline at end of file diff --git a/d2x/cpp/common.lua b/d2x/cpp/common.lua deleted file mode 100644 index 4a14d17..0000000 --- a/d2x/cpp/common.lua +++ /dev/null @@ -1,29 +0,0 @@ -function get_local_lang() ---local config = platform.get_config_info() - local local_lang = "en" -- Default language - -- TODO: config language by xlings.json - if is_host("linux") then - local tmp_local_lang = os.getenv("LANG") or "en" - if tmp_local_lang:find("zh") then - local_lang = "zh" - end - elseif is_host("windows") then - local tmp_local_lang = nil - if find_tool("wmic") then -- Windows 10 and earlier - -- wmic is deprecated in Windows 11, but still available - tmp_local_lang = os.iorun([[wmic os get locale]]) - else -- win11+ - tmp_local_lang = os.iorun([[powershell -NoProfile -ExecutionPolicy Bypass -Command "'{0:X4}' -f (Get-Culture).LCID"]]) - end - if tmp_local_lang and tmp_local_lang:find("0804") then - local_lang = "zh" - end - elseif is_host("macosx") then - local tmp_local_lang = os.iorun([[defaults read -g AppleLocale]]) - if tmp_local_lang and tmp_local_lang:find("zh") then - local_lang = "zh" - end - end - - return local_lang -end diff --git a/d2x/cpp/honly_logger.hpp b/d2x/cpp/honly_logger.hpp deleted file mode 100644 index 0edda51..0000000 --- a/d2x/cpp/honly_logger.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef LOGGER_HPP__HONLY -#define LOGGER_HPP__HONLY - -#include - -#ifndef HONLY_LOGGER_TAG -#define HONLY_LOGGER_TAG "HONLY" -#endif - -#define LOG_ENABLE true -#define _HONLY_LOG(fd, ...) if (LOG_ENABLE) { fprintf (fd, __VA_ARGS__); fprintf (fd, "\033[0m\n"); fflush(stdout); } -#define HONLY_LOGI_P(...) { fprintf (stdout, "\033[32m[%s LOGI]: - ", HONLY_LOGGER_TAG); _HONLY_LOG(stdout, __VA_ARGS__); } -#define HONLY_LOGI(...) { fprintf (stdout, "\033[32m[%s LOGI]: %s: %s:%d - ", HONLY_LOGGER_TAG, __func__, __FILE__, __LINE__); _HONLY_LOG(stdout, __VA_ARGS__); } -#define HONLY_LOGD(...) { fprintf (stdout, "\033[37m[%s LOGD]: %s: %s:%d - ", HONLY_LOGGER_TAG, __func__, __FILE__, __LINE__); _HONLY_LOG(stdout, __VA_ARGS__); } -#define HONLY_LOGW(...) { fprintf (stdout, "\033[33m[%s LOGW]: %s: %s:%d - ", HONLY_LOGGER_TAG, __func__, __FILE__, __LINE__); _HONLY_LOG(stdout, __VA_ARGS__); } -#define HONLY_LOGE(...) { fprintf (stdout, "\033[31m[%s LOGE]: %s: %s:%d - ❌ | ", HONLY_LOGGER_TAG, __func__, __FILE__, __LINE__); _HONLY_LOG(stdout, __VA_ARGS__); } - -#endif \ No newline at end of file diff --git a/d2x/mcpp.toml b/d2x/mcpp.toml new file mode 100644 index 0000000..4f274ef --- /dev/null +++ b/d2x/mcpp.toml @@ -0,0 +1,9 @@ +[package] +name = "d2x" +version = "0.2.0" +description = "d2x 练习库:检查点、路障、侧信道上报(纯模块 import d2x,零宏)" +license = "Apache-2.0" +standard = "c++23" + +[targets.d2x] +kind = "lib" diff --git a/d2x/mcpp/common.cppm b/d2x/mcpp/common.cppm deleted file mode 100644 index c88709c..0000000 --- a/d2x/mcpp/common.cppm +++ /dev/null @@ -1,5 +0,0 @@ -module; - -#include - -export module d2x.project.common; \ No newline at end of file diff --git a/d2x/src/d2x.cppm b/d2x/src/d2x.cppm new file mode 100644 index 0000000..3483c3c --- /dev/null +++ b/d2x/src/d2x.cppm @@ -0,0 +1,200 @@ +module; + +// C 运行时符号走全局模块片段:atexit/_Exit/getenv/fopen 一族 import std 不提供。 +#include +#include + +export module d2x; + +import std; + +// d2x 练习库 —— 唯一路径,纯模块,零宏。练习侧 `import d2x;` 即可。 +// +// 填空占位符 D2X_YOUR_ANSWER 不在这里:它是**纯约定**,不定义在任何地方。 +// 一个未定义的标识符本身就是编译错误,而且报错正好指着要填的位置 +// (`unknown type name 'D2X_YOUR_ANSWER'`)。所以它不需要任何导入、在 +// 模块化练习里天然可用、拷进 Compiler Explorer 也成立。 +// +// 判定信号走两条路,各有消费者: +// 进程退出码 —— 有失败检查点或未拆的 wait() 时退出码变 1。这让裸 +// `mcpp test` 不需要懂任何 d2x 概念就能显示对错。 +// 侧信道 v2 —— D2X_RESULT_FILE 指定的 NDJSON 文件,Provider 读它 +// 把「为什么失败」变成结构化诊断、把 wait 区分成 blocked。 +// 未设置时不写文件:学习者直接跑二进制零摩擦。 +// +// 可见输出的设计(学习者直接看到的三类输出行): +// ✅ | ( == ) 绿 +// ❌ | ( == ) -> : 红 +// 🚧 | Delete the d2x::wait() to continue -> : 黄 +// 标识就是 emoji 本身,不带日志框架前缀;file 尽量以仓库相对路径展示 +// (定位用的绝对路径走侧信道,展示归展示、定位归定位)。 + +namespace d2x::detail { + +int g_failures = 0; +int g_waits = 0; +bool g_hooked = false; + +// 进程正常退出时,若有失败检查点或未拆的路障,把退出码改成 1。 +// 只在这两种情况下覆盖——练习自己 return 非 0 时不动它。 +// _Exit 跳过后续清理,所以先冲刷 stdio。 +void exit_hook() { + if (g_failures > 0 || g_waits > 0) { + std::fflush(stdout); + std::fflush(stderr); + std::_Exit(1); + } +} + +void ensure_hook() { + if (!g_hooked) { + g_hooked = true; + std::atexit(exit_hook); + } +} + +inline std::string escape(std::string_view s) { + std::string out; + out.reserve(s.size() + 8); + for (unsigned char c : s) { + switch (c) { + case '"': out += "\\\""; break; + case '\\': out += "\\\\"; break; + case '\n': out += "\\n"; break; + case '\r': out += "\\r"; break; + case '\t': out += "\\t"; break; + default: + if (c < 0x20) out += std::format("\\u{:04x}", static_cast(c)); + else out += static_cast(c); + } + } + return out; +} + +// 每次都重新打开并追加。比持有 FILE* 慢,但换来两个性质: +// 进程异常终止不丢已写入的行;无需依赖静态析构顺序。 +inline void emit(const std::string& json_line) { + const char* path = std::getenv("D2X_RESULT_FILE"); + if (!path || !*path) return; // 学习者直接运行:什么都不做 + + if (std::FILE* f = std::fopen(path, "a")) { + std::fputs(json_line.c_str(), f); + std::fputc('\n', f); + std::fclose(f); + } +} + +inline void report_assert(bool ok, std::string_view what, + const std::string& expected, const std::string& actual, + const char* file, int line) { + std::string out = "{\"v\":2,\"kind\":\"assert\",\"ok\":"; + out += ok ? "true" : "false"; + out += ",\"what\":\"" + escape(what) + "\""; + out += ",\"expected\":\"" + escape(expected) + "\""; + out += ",\"actual\":\"" + escape(actual) + "\""; + out += ",\"file\":\"" + escape(file ? file : "") + "\""; + out += ",\"line\":" + std::to_string(line) + "}"; + emit(out); +} + +inline void report_wait(const char* file, int line) { + std::string out = "{\"v\":2,\"kind\":\"wait\",\"file\":\""; + out += escape(file ? file : ""); + out += "\",\"line\":" + std::to_string(line) + "}"; + emit(out); +} + +// std::formattable 是 SFINAE 安全的探测;若直接在 requires 表达式里写 +// std::format("{}", v),会触发未特化 std::formatter 的 static_assert +// 硬错误(scoped enum、自定义类型的练习中已实际出现)。 +inline std::string show_impl(const auto& v) { + using T = std::remove_cvref_t; + if constexpr (std::formattable) return std::format("{}", v); + else return {}; +} + +// 展示用路径:能剥掉当前工作目录前缀就剥(学习者从仓库根跑时看到 +// src/cpp11/tests/... 而不是一长串 /home/...)。剥不掉就原样。 +inline std::string show_path(const char* file) { + if (!file) return {}; + std::string_view path(file); + std::error_code ec; + auto cwd = std::filesystem::current_path(ec); + if (!ec) { + auto prefix = cwd.generic_string() + "/"; + if (path.starts_with(prefix)) return std::string(path.substr(prefix.size())); + } + return std::string(path); +} + +constexpr std::string_view kGreen = "\033[32m"; +constexpr std::string_view kRed = "\033[31m"; +constexpr std::string_view kYellow = "\033[33m"; +constexpr std::string_view kReset = "\033[0m"; + +} // namespace d2x::detail + +export namespace d2x { + +// 检查点。`what` 是给学习者看的语义标签(通常是表达式原文——c++23 没有 +// 反射拿不到 #expr,由撰稿或迁移脚本填写)。 +inline bool check(bool ok, std::string_view what = {}, + std::source_location loc = std::source_location::current()) { + d2x::detail::ensure_hook(); + if (!ok) ++d2x::detail::g_failures; + + auto label = what.empty() ? std::string_view("check") : what; + d2x::detail::report_assert(ok, label, "true", ok ? "true" : "false", + loc.file_name(), static_cast(loc.line())); + if (ok) std::print("{}✅ | {}{}\n", d2x::detail::kGreen, label, d2x::detail::kReset); + else std::print("{}❌ | {} -> {}:{}{}\n", d2x::detail::kRed, label, + d2x::detail::show_path(loc.file_name()), loc.line(), + d2x::detail::kReset); + std::fflush(stdout); + return ok; +} + +template +inline bool check_eq(const A& a, const B& b, std::string_view what = {}, + std::source_location loc = std::source_location::current()) { + d2x::detail::ensure_hook(); + const bool ok = (a == b); + if (!ok) ++d2x::detail::g_failures; + + auto sa = d2x::detail::show_impl(a); + auto sb = d2x::detail::show_impl(b); + auto label = what.empty() ? std::format("{} == {}", sa, sb) : std::string(what); + + d2x::detail::report_assert(ok, label, sb, sa, + loc.file_name(), static_cast(loc.line())); + + if (ok) std::print("{}✅ | {} ({} == {}){}\n", + d2x::detail::kGreen, label, sa, sb, d2x::detail::kReset); + else std::print("{}❌ | {} ({} == {}) -> {}:{}{}\n", + d2x::detail::kRed, label, sa, sb, + d2x::detail::show_path(loc.file_name()), loc.line(), + d2x::detail::kReset); + std::fflush(stdout); + return ok; +} + +// 恒等透传:标记「这一行是教学观测点,别删」。 +template +constexpr decltype(auto) dont_delete_this(T&& x) { + return std::forward(x); +} + +// 显式路障:学习者读完说明、删掉这一行才算真正完成这一题。 +// 记录后照常返回(不中断程序)——后续检查点还要跑;退出码由 exit_hook +// 收口,Provider 再根据侧信道把「只剩 wait」区分成 blocked。 +inline void wait(std::source_location loc = std::source_location::current()) { + d2x::detail::ensure_hook(); + ++d2x::detail::g_waits; + d2x::detail::report_wait(loc.file_name(), static_cast(loc.line())); + std::print("{}🚧 | Delete the d2x::wait() to continue -> {}:{}{}\n", + d2x::detail::kYellow, d2x::detail::show_path(loc.file_name()), + loc.line(), d2x::detail::kReset); + std::fflush(stdout); +} + +} // namespace d2x diff --git a/dslings/cpp11/xmake.lua b/dslings/cpp11/xmake.lua deleted file mode 100644 index e7dbdae..0000000 --- a/dslings/cpp11/xmake.lua +++ /dev/null @@ -1,195 +0,0 @@ -if is_host("windows") then - set_languages("cxx14") -else - set_languages("cxx11") -end - --- target: cpp11-00-auto-and-decltype - -target("cpp11-00-auto-and-decltype") - set_kind("binary") - add_files("00-auto-and-decltype-0.cpp") -target("cpp11-00-auto-and-decltype-1") - set_kind("binary") - add_files("00-auto-and-decltype-1.cpp") -target("cpp11-00-auto-and-decltype-2") - set_kind("binary") - add_files("00-auto-and-decltype-2.cpp") -target("cpp11-00-auto-and-decltype-3") - set_kind("binary") - add_files("00-auto-and-decltype-3.cpp") -target("cpp11-00-auto-and-decltype-4") - set_kind("binary") - add_files("00-auto-and-decltype-4.cpp") -target("cpp11-00-auto-and-decltype-5") - set_kind("binary") - add_files("00-auto-and-decltype-5.cpp") - --- target: cpp11-01-default-and-delete - -target("cpp11-01-default-and-delete-0") - set_kind("binary") - add_files("01-default-and-delete-0.cpp") - -target("cpp11-01-default-and-delete-1") - set_kind("binary") - add_files("01-default-and-delete-1.cpp") - -target("cpp11-01-default-and-delete-2") - set_kind("binary") - add_files("01-default-and-delete-2.cpp") - --- target: cpp11-02-final-and-override - -target("cpp11-02-final-and-override-0") - add_files("02-final-and-override-0.cpp") - -target("cpp11-02-final-and-override-1") - add_files("02-final-and-override-1.cpp") - -target("cpp11-02-final-and-override-2") - add_files("02-final-and-override-2.cpp") - --- target: cpp11-03-trailing-return-type - -target("cpp11-03-trailing-return-type") - add_files("03-trailing-return-type.cpp") - --- target: cpp11-04-rvalue-references - -target("cpp11-04-rvalue-references") - set_optimize("none") - add_cxxflags("-fno-elide-constructors") - add_files("04-rvalue-references.cpp") - --- target: cpp11-05-move-semantics - -target("cpp11-05-move-semantics-0") - add_files("05-move-semantics-0.cpp") - -target("cpp11-05-move-semantics-1") - add_files("05-move-semantics-1.cpp") - -target("cpp11-05-move-semantics-2") - add_files("05-move-semantics-2.cpp") - --- target: cpp11-06-scoped-enums - -target("cpp11-06-scoped-enums-0") - add_files("06-scoped-enums-0.cpp") - -target("cpp11-06-scoped-enums-1") - add_files("06-scoped-enums-1.cpp") - --- target: cpp11-07-constexpr - -target("cpp11-07-constexpr-0") - add_cxxflags("-Wpedantic -Werror") - add_files("07-constexpr-0.cpp") - -target("cpp11-07-constexpr-1") - add_files("07-constexpr-1.cpp") - --- target: cpp11-08-literal-type - -target("cpp11-08-literal-type-0") - set_languages("c++17") -- TODO: optimize it - add_files("08-literal-type-0.cpp") - -target("cpp11-08-literal-type-1") - add_files("08-literal-type-1.cpp") - --- target: cpp11-09-list-initialization - -target("cpp11-09-list-initialization-0") - add_files("09-list-initialization-0.cpp") - -target("cpp11-09-list-initialization-1") - add_files("09-list-initialization-1.cpp") - -target("cpp11-09-list-initialization-2") - add_files("09-list-initialization-2.cpp") - -target("cpp11-09-list-initialization-3") - add_files("09-list-initialization-3.cpp") - --- target: cpp11-10-delegating-constructors - -target("cpp11-10-delegating-constructors-0") - add_files("10-delegating-constructors-0.cpp") - -target("cpp11-10-delegating-constructors-1") - add_files("10-delegating-constructors-1.cpp") - --- target: cpp11-11-inherited-constructors - -target("cpp11-11-inherited-constructors-0") - add_files("11-inherited-constructors-0.cpp") - -target("cpp11-11-inherited-constructors-1") - add_files("11-inherited-constructors-1.cpp") - -target("cpp11-11-inherited-constructors-2") - add_files("11-inherited-constructors-2.cpp") - --- target: cpp11-12-nullptr - -target("cpp11-12-nullptr-0") - add_files("12-nullptr-0.cpp") - -target("cpp11-12-nullptr-1") - add_files("12-nullptr-1.cpp") - -target("cpp11-12-nullptr-2") - add_files("12-nullptr-2.cpp") - --- target: cpp11-13-long-long -target("cpp11-13-long-long-0") - add_files("13-long-long-0.cpp") - -target("cpp11-13-long-long-1") - add_files("13-long-long-1.cpp") - --- target: cpp11-14-type-alias - -target("cpp11-14-type-alias-0") - add_files("14-type-alias-0.cpp") - -target("cpp11-14-type-alias-1") - add_files("14-type-alias-1.cpp") - -target("cpp11-14-type-alias-2") - add_files("14-type-alias-2.cpp") - -target("cpp11-14-type-alias-3") - add_files("14-type-alias-3.cpp") - --- target: cpp11-15-variadic-templates - -target("cpp11-15-variadic-templates-0") - add_files("15-variadic-templates-0.cpp") - -target("cpp11-15-variadic-templates-1") - add_files("15-variadic-templates-1.cpp") - --- target: cpp11-16-generalized-unions - -target("cpp11-16-generalized-unions-0") - add_files("16-generalized-unions-0.cpp") - -target("cpp11-16-generalized-unions-1") - add_files("16-generalized-unions-1.cpp") - -target("cpp11-16-generalized-unions-2") - add_files("16-generalized-unions-2.cpp") - --- target: cpp11-17-pod-type - -target("cpp11-17-pod-type-0") - add_files("17-pod-type-0.cpp") - -target("cpp11-17-pod-type-1") - add_files("17-pod-type-1.cpp") - -target("cpp11-17-pod-type-2") - add_files("17-pod-type-2.cpp") diff --git a/dslings/cpp14/xmake.lua b/dslings/cpp14/xmake.lua deleted file mode 100644 index 8a21cbf..0000000 --- a/dslings/cpp14/xmake.lua +++ /dev/null @@ -1,11 +0,0 @@ -set_languages("cxx14") - --- target: cpp14-00-generic-lambdas - -target("cpp14-00-generic-lambdas-0") - set_kind("binary") - add_files("00-generic-lambdas-0.cpp") - -target("cpp14-00-generic-lambdas-1") - set_kind("binary") - add_files("00-generic-lambdas-1.cpp") diff --git a/dslings/cpp17/README.md b/dslings/cpp17/README.md deleted file mode 100644 index f87f5c1..0000000 --- a/dslings/cpp17/README.md +++ /dev/null @@ -1 +0,0 @@ -# TODO \ No newline at end of file diff --git a/dslings/cpp20/README.md b/dslings/cpp20/README.md deleted file mode 100644 index f87f5c1..0000000 --- a/dslings/cpp20/README.md +++ /dev/null @@ -1 +0,0 @@ -# TODO \ No newline at end of file diff --git a/dslings/cpp23/README.md b/dslings/cpp23/README.md deleted file mode 100644 index f87f5c1..0000000 --- a/dslings/cpp23/README.md +++ /dev/null @@ -1 +0,0 @@ -# TODO \ No newline at end of file diff --git a/dslings/en/cpp11/xmake.lua b/dslings/en/cpp11/xmake.lua deleted file mode 100644 index 6daeb9e..0000000 --- a/dslings/en/cpp11/xmake.lua +++ /dev/null @@ -1,192 +0,0 @@ -if is_host("windows") then - set_languages("cxx14") -else - set_languages("cxx11") -end - --- target: cpp11-00-auto-and-decltype - -target("cpp11-00-auto-and-decltype") - set_kind("binary") - add_files("00-auto-and-decltype-0.cpp") -target("cpp11-00-auto-and-decltype-1") - set_kind("binary") - add_files("00-auto-and-decltype-1.cpp") -target("cpp11-00-auto-and-decltype-2") - set_kind("binary") - add_files("00-auto-and-decltype-2.cpp") -target("cpp11-00-auto-and-decltype-3") - set_kind("binary") - add_files("00-auto-and-decltype-3.cpp") -target("cpp11-00-auto-and-decltype-4") - set_kind("binary") - add_files("00-auto-and-decltype-4.cpp") - --- target: cpp11-01-default-and-delete - -target("cpp11-01-default-and-delete-0") - set_kind("binary") - add_files("01-default-and-delete-0.cpp") - -target("cpp11-01-default-and-delete-1") - set_kind("binary") - add_files("01-default-and-delete-1.cpp") - -target("cpp11-01-default-and-delete-2") - set_kind("binary") - add_files("01-default-and-delete-2.cpp") - --- target: cpp11-02-final-and-override - -target("cpp11-02-final-and-override-0") - add_files("02-final-and-override-0.cpp") - -target("cpp11-02-final-and-override-1") - add_files("02-final-and-override-1.cpp") - -target("cpp11-02-final-and-override-2") - add_files("02-final-and-override-2.cpp") - --- target: cpp11-03-trailing-return-type - -target("cpp11-03-trailing-return-type") - add_files("03-trailing-return-type.cpp") - --- target: cpp11-04-rvalue-references - -target("cpp11-04-rvalue-references") - set_optimize("none") - add_cxxflags("-fno-elide-constructors") - add_files("04-rvalue-references.cpp") - --- target: cpp11-05-move-semantics - -target("cpp11-05-move-semantics-0") - add_files("05-move-semantics-0.cpp") - -target("cpp11-05-move-semantics-1") - add_files("05-move-semantics-1.cpp") - -target("cpp11-05-move-semantics-2") - add_files("05-move-semantics-2.cpp") - --- target: cpp11-06-scoped-enums - -target("cpp11-06-scoped-enums-0") - add_files("06-scoped-enums-0.cpp") - -target("cpp11-06-scoped-enums-1") - add_files("06-scoped-enums-1.cpp") - --- target: cpp11-07-constexpr - -target("cpp11-07-constexpr-0") - add_cxxflags("-Wpedantic -Werror") - add_files("07-constexpr-0.cpp") - -target("cpp11-07-constexpr-1") - add_files("07-constexpr-1.cpp") - --- target: cpp11-08-literal-type - -target("cpp11-08-literal-type-0") - set_languages("c++17") -- TODO: optimize it - add_files("08-literal-type-0.cpp") - -target("cpp11-08-literal-type-1") - add_files("08-literal-type-1.cpp") - --- target: cpp11-09-list-initialization - -target("cpp11-09-list-initialization-0") - add_files("09-list-initialization-0.cpp") - -target("cpp11-09-list-initialization-1") - add_files("09-list-initialization-1.cpp") - -target("cpp11-09-list-initialization-2") - add_files("09-list-initialization-2.cpp") - -target("cpp11-09-list-initialization-3") - add_files("09-list-initialization-3.cpp") - --- target: cpp11-10-delegating-constructors - -target("cpp11-10-delegating-constructors-0") - add_files("10-delegating-constructors-0.cpp") - -target("cpp11-10-delegating-constructors-1") - add_files("10-delegating-constructors-1.cpp") - --- target: cpp11-11-inherited-constructors - -target("cpp11-11-inherited-constructors-0") - add_files("11-inherited-constructors-0.cpp") - -target("cpp11-11-inherited-constructors-1") - add_files("11-inherited-constructors-1.cpp") - -target("cpp11-11-inherited-constructors-2") - add_files("11-inherited-constructors-2.cpp") - --- target: cpp11-12-nullptr - -target("cpp11-12-nullptr-0") - add_files("12-nullptr-0.cpp") - -target("cpp11-12-nullptr-1") - add_files("12-nullptr-1.cpp") - -target("cpp11-12-nullptr-2") - add_files("12-nullptr-2.cpp") - --- target: cpp11-13-long-long -target("cpp11-13-long-long-0") - add_files("13-long-long-0.cpp") - -target("cpp11-13-long-long-1") - add_files("13-long-long-1.cpp") - --- target: cpp11-14-type-alias - -target("cpp11-14-type-alias-0") - add_files("14-type-alias-0.cpp") - -target("cpp11-14-type-alias-1") - add_files("14-type-alias-1.cpp") - -target("cpp11-14-type-alias-2") - add_files("14-type-alias-2.cpp") - -target("cpp11-14-type-alias-3") - add_files("14-type-alias-3.cpp") - --- target: cpp11-15-variadic-templates - -target("cpp11-15-variadic-templates-0") - add_files("15-variadic-templates-0.cpp") - -target("cpp11-15-variadic-templates-1") - add_files("15-variadic-templates-1.cpp") - --- target: cpp11-16-generalized-unions - -target("cpp11-16-generalized-unions-0") - add_files("16-generalized-unions-0.cpp") - -target("cpp11-16-generalized-unions-1") - add_files("16-generalized-unions-1.cpp") - -target("cpp11-16-generalized-unions-2") - add_files("16-generalized-unions-2.cpp") - --- target: cpp11-17-pod-type - -target("cpp11-17-pod-type-0") - add_files("17-pod-type-0.cpp") - -target("cpp11-17-pod-type-1") - add_files("17-pod-type-1.cpp") - -target("cpp11-17-pod-type-2") - add_files("17-pod-type-2.cpp") diff --git a/dslings/en/cpp14/xmake.lua b/dslings/en/cpp14/xmake.lua deleted file mode 100644 index 8a21cbf..0000000 --- a/dslings/en/cpp14/xmake.lua +++ /dev/null @@ -1,11 +0,0 @@ -set_languages("cxx14") - --- target: cpp14-00-generic-lambdas - -target("cpp14-00-generic-lambdas-0") - set_kind("binary") - add_files("00-generic-lambdas-0.cpp") - -target("cpp14-00-generic-lambdas-1") - set_kind("binary") - add_files("00-generic-lambdas-1.cpp") diff --git a/dslings/en/hello-mcpp.cpp b/dslings/en/hello-mcpp.cpp deleted file mode 100644 index f9f33b6..0000000 --- a/dslings/en/hello-mcpp.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// mcpp-standard: https://github.com/Sunrisepeak/mcpp-standard -// license: Apache-2.0 -// file: dslings/hello-mcpp.cpp -// -// Exercise: Automated Code Practice Usage Tutorial -// -// Tips: -// This project is an automated code practice project built using the xlings tool. -// By executing `d2x checker` in the project root directory, you enter the -// "compiler-driven development mode" for automatic code practice detection. -// You need to modify errors in the code based on console error messages and prompts. -// After fixing all compilation errors and runtime checkpoints, you can delete or -// comment out the D2X_WAIT macro in the code to automatically proceed to the next exercise. -// -// - D2X_WAIT: This macro is used to isolate different exercises. You can delete or -// comment out this macro to proceed to the next exercise. -// - d2x_assert_eq: This macro is used for runtime checkpoints. You need to fix -// errors in the code so that all checkpoints pass. -// - D2X_YOUR_ANSWER: This macro indicates code that needs to be modified, generally -// used for code completion (replace this macro with correct code) -// -// Docs: -// - https://github.com/Sunrisepeak/mcpp-standard/blob/main/book/src/chapter_1.md -// - book/src/chapter_1.md -// -// Auto-Checker command: -// -// d2x checker hello-mcpp -// - -#include - -// You can observe "real-time" changes in the console when modifying code - -int main() { - - std::cout << "hello, mcpp!" << std:endl; // 0. Fix this compilation error - - int a = 1.1; // 1. Fix this runtime error, change int to double to pass the check - - d2x_assert_eq(a, 1.1); // 2. Runtime checkpoint, need to fix code to pass all checkpoints (cannot directly delete checkpoint code) - - D2X_YOUR_ANSWER b = a; // 3. Fix this compilation error, give b an appropriate type - - d2x_assert_eq(b, 1); // 4. Runtime checkpoint 2 - - D2X_WAIT // 5. Delete or comment out this macro to proceed to the next exercise (project formal code practice) - - return 0; -} - -//// --- More detailed introduction | | | -// V V V -/* - -# [[ Console Output Interpretation ]] - -🌏Progress: [>----------] 0/10 -->> Shows current exercise progress - -[Target: 00-0-hello-mcpp] - normal -->> Current exercise name - -❌ Error: Compilation/Running failed for dslings/hello-mcpp.cpp -->> Shows detection status - - The code exist some error! - ----------C-Output--------- - Compiler output information -[HONLY LOGW]: main: dslings/hello-mcpp.cpp:24 - ❌ | a == 1.1 (1 == 1.100000) -->> Error prompt and location (line 24) -[HONLY LOGW]: main: dslings/hello-mcpp.cpp:26 - 🥳 Delete the D2X_WAIT to continue... - - -AI-Tips-Config: https://xlings.d2learn.org/en/documents/d2x/intro.html -->> AI tips (requires configuring large model key, optional) - ----------E-Files--------- -dslings/hello-mcpp.cpp -->> Current file being checked -------------------------- - -Homepage: https://github.com/openxlings/xlings - -*/ diff --git a/dslings/en/xmake.lua b/dslings/en/xmake.lua deleted file mode 100644 index 7678d9a..0000000 --- a/dslings/en/xmake.lua +++ /dev/null @@ -1,6 +0,0 @@ -target("00-0-hello-mcpp") - set_languages("cxx11") - add_files("hello-mcpp.cpp") - -includes("cpp11") -includes("cpp14") diff --git a/dslings/hello-mcpp.cpp b/dslings/hello-mcpp.cpp deleted file mode 100644 index 9cf4da3..0000000 --- a/dslings/hello-mcpp.cpp +++ /dev/null @@ -1,74 +0,0 @@ -// d2mcpp: https://github.com/mcpp-community/d2mcpp -// license: Apache-2.0 -// file: dslings/hello-mcpp.cpp -// -// Exercise/练习: 自动化代码练习使用教学 -// -// Tips/提示: -// 该项目是使用xlings工具搭建的自动化代码练习项目, 通过在项目根目录下 -// 执行 d2x checker 进入"编译器驱动开发模式"的练习代码自动检测. -// 你需要根据控制台的报错和提示信息, 修改代码中的错误. 当修复所有编译错误和 -// 运行时检查点后, 你可以删除或注释掉代码中的 D2X_WAIT 宏, 会自动进入下一个练习. -// -// - D2X_WAIT: 该宏用于隔离不同练习, 你可以删除或注释掉该宏, 进入下一个练习. -// - d2x_assert_eq: 该宏用于运行时检查点, 你需要修复代码中的错误, 使得所有 -// - D2X_YOUR_ANSWER: 该宏用于提示你需要修改的代码, 一般用于代码填空(即用正确的代码替换这个宏) -// -// Docs/文档: -// - https://github.com/mcpp-community/d2mcpp/blob/main/book/src/chapter_1.md -// - book/src/chapter_1.md -// -// Auto-Checker/自动检测命令: -// -// d2x checker hello-mcpp -// - -#include - -// 修改代码时可以观察到控制台"实时"的变化 - -int main() { - - std::cout << "hello, mcpp!" << std:endl; // 0.修复这个编译错误 - - int a = 1.1; // 1.修复这个运行时错误, 修改int为double, 通过检查 - - d2x_assert_eq(a, 1.1); // 2.运行时检查点, 需要修复代码通过所有检查点(不能直接删除检查点代码) - - D2X_YOUR_ANSWER b = a; // 3.修复这个编译错误, 给b一个合适的类型 - - d2x_assert_eq(b, 1); // 4.运行时检查点2 - - D2X_WAIT // 5.删除或注释掉这个宏, 进入下一个练习(项目正式代码练习) - - return 0; -} - -//// --- 更多详细介绍 | | | -// V V V -/* - -# [[ 控制台输出解读 ]] - -🌏Progress: [>----------] 0/10 -->> 显示当前的练习进度 - -[Target: 00-0-hello-mcpp] - normal -->> 当前的练习名 - -❌ Error: Compilation/Running failed for dslings/hello-mcpp.cpp -->> 显示检测状态 - - The code exist some error! - ----------C-Output--------- - 编译器输出信息 -[HONLY LOGW]: main: dslings/hello-mcpp.cpp:24 - ❌ | a == 1.1 (1 == 1.100000) -->> 错误提示及位置(24行) -[HONLY LOGW]: main: dslings/hello-mcpp.cpp:26 - 🥳 Delete the D2X_WAIT to continue... - - -AI-Tips-Config: https://xlings.d2learn.org/documents/d2x/intro.html -->> AI提示(需要配置大模型的key, 可不使用) - ----------E-Files--------- -dslings/hello-mcpp.cpp -->> 当前检测的文件 -------------------------- - -Homepage: https://github.com/openxlings/xlings - -*/ \ No newline at end of file diff --git a/dslings/xmake.lua b/dslings/xmake.lua deleted file mode 100644 index 32c5a95..0000000 --- a/dslings/xmake.lua +++ /dev/null @@ -1,23 +0,0 @@ -if is_host("windows") then - set_encodings("source:utf-8", "target:utf-8") - set_toolchains("gcc") - add_ldflags("-static") -end - -option("lang") - set_default("en") - set_description("Language: en or zh") - -local lang = get_config("lang") - -if lang == "zh" then - - target("00-0-hello-mcpp") - set_languages("cxx11") - add_files("hello-mcpp.cpp") - - includes("cpp11") - includes("cpp14") -else - includes("en") -end diff --git a/mcpp.toml b/mcpp.toml new file mode 100644 index 0000000..0635035 --- /dev/null +++ b/mcpp.toml @@ -0,0 +1,10 @@ +# d2mcpp 根 workspace。练习即测试:每个 C++ 标准对应 src/ 下的一个 mcpp 工程, +# 练习即该工程的 tests/,mcpp test 的测试报告即学习进度;d2x checker 复用同一条链路。 +# d2x/ 目录包含练习库(import d2x)与 Provider(buildtools/)。 +[workspace] +members = [ + "d2x", + "src/intro", "src/cpp11", "src/cpp14", + "src/en/intro", "src/en/cpp11", "src/en/cpp14", + "d2x/buildtools", +] diff --git a/solutions/cpp11/00-auto-and-decltype-0.cpp b/solutions/cpp11/00-auto-and-decltype/0.cpp similarity index 70% rename from solutions/cpp11/00-auto-and-decltype-0.cpp rename to solutions/cpp11/00-auto-and-decltype/0.cpp index 43ab73d..56a61f7 100644 --- a/solutions/cpp11/00-auto-and-decltype-0.cpp +++ b/solutions/cpp11/00-auto-and-decltype/0.cpp @@ -6,7 +6,8 @@ // 教程练习入口: dslings/cpp11/00-auto-and-decltype-0.cpp // -#include +import std; +import d2x; int main() { @@ -23,12 +24,12 @@ int main() { auto c1 = c; // c1: char decltype(c) c2 = c; // c2: char - d2x_assert_eq(a, a1); - d2x_assert_eq(a1, a2); - d2x_assert_eq(b, b1); - d2x_assert_eq(b1, b2); - d2x_assert_eq(c, c1); - d2x_assert_eq(c1, c2); + d2x::check_eq(a, a1, "a == a1"); + d2x::check_eq(a1, a2, "a1 == a2"); + d2x::check_eq(b, b1, "b == b1"); + d2x::check_eq(b1, b2, "b1 == b2"); + d2x::check_eq(c, c1, "c == c1"); + d2x::check_eq(c1, c2, "c1 == c2"); return 0; } diff --git a/solutions/cpp11/00-auto-and-decltype-1.cpp b/solutions/cpp11/00-auto-and-decltype/1.cpp similarity index 74% rename from solutions/cpp11/00-auto-and-decltype-1.cpp rename to solutions/cpp11/00-auto-and-decltype/1.cpp index f301144..e9be137 100644 --- a/solutions/cpp11/00-auto-and-decltype-1.cpp +++ b/solutions/cpp11/00-auto-and-decltype/1.cpp @@ -6,7 +6,8 @@ // 教程练习入口: dslings/cpp11/00-auto-and-decltype-1.cpp // -#include +import std; +import d2x; int main() { @@ -24,10 +25,10 @@ int main() { auto c1 = 1 + c; // int decltype(2 + 'a') c2 = 2 + 'a'; - d2x_assert_eq(a2, a + 2 + 1.1); - d2x_assert_eq(b1, a + 0.1); - d2x_assert_eq(c1, 1 + c); - d2x_assert_eq(c2, 2 + 'a'); + d2x::check_eq(a2, a + 2 + 1.1, "a2 == a + 2 + 1.1"); + d2x::check_eq(b1, a + 0.1, "b1 == a + 0.1"); + d2x::check_eq(c1, 1 + c, "c1 == 1 + c"); + d2x::check_eq(c2, 2 + 'a', "c2 == 2 + 'a'"); return 0; } diff --git a/solutions/cpp11/00-auto-and-decltype-2.cpp b/solutions/cpp11/00-auto-and-decltype/2.cpp similarity index 83% rename from solutions/cpp11/00-auto-and-decltype-2.cpp rename to solutions/cpp11/00-auto-and-decltype/2.cpp index e3d7c5a..528682c 100644 --- a/solutions/cpp11/00-auto-and-decltype-2.cpp +++ b/solutions/cpp11/00-auto-and-decltype/2.cpp @@ -6,11 +6,9 @@ // 教程练习入口: dslings/cpp11/00-auto-and-decltype-2.cpp // -#include +import std; +import d2x; -#include -#include -#include int add_func(int a, int b) { return a + b; @@ -41,8 +39,8 @@ int main() { minus_func }; - d2x_assert_eq(funcVec[0](1, 2), 3); - d2x_assert_eq(funcVec[1](1, 2), -1); + d2x::check_eq(funcVec[0](1, 2), 3, "funcVec[0](1, 2) == 3"); + d2x::check_eq(funcVec[1](1, 2), -1, "funcVec[1](1, 2) == -1"); return 0; } diff --git a/solutions/cpp11/00-auto-and-decltype-3.cpp b/solutions/cpp11/00-auto-and-decltype/3.cpp similarity index 69% rename from solutions/cpp11/00-auto-and-decltype-3.cpp rename to solutions/cpp11/00-auto-and-decltype/3.cpp index 47c8b2e..a83aaa4 100644 --- a/solutions/cpp11/00-auto-and-decltype-3.cpp +++ b/solutions/cpp11/00-auto-and-decltype/3.cpp @@ -6,10 +6,9 @@ // 教程练习入口: dslings/cpp11/00-auto-and-decltype-3.cpp // -#include +import std; +import d2x; -#include -#include // 3. 函数返回值类型 @@ -24,9 +23,9 @@ auto minus_func(T1 a, T2 b) -> decltype(a - b) { int main() { - d2x_assert_eq(minus_func(1, 2), -1); - d2x_assert_eq(minus_func(2, 1), 1); - d2x_assert_eq(minus_func(1, 2.1), -1.1); + d2x::check_eq(minus_func(1, 2), -1, "minus_func(1, 2) == -1"); + d2x::check_eq(minus_func(2, 1), 1, "minus_func(2, 1) == 1"); + d2x::check_eq(minus_func(1, 2.1), -1.1, "minus_func(1, 2.1) == -1.1"); return 0; } diff --git a/solutions/cpp11/00-auto-and-decltype-4.cpp b/solutions/cpp11/00-auto-and-decltype/4.cpp similarity index 66% rename from solutions/cpp11/00-auto-and-decltype-4.cpp rename to solutions/cpp11/00-auto-and-decltype/4.cpp index caddb29..697f430 100644 --- a/solutions/cpp11/00-auto-and-decltype-4.cpp +++ b/solutions/cpp11/00-auto-and-decltype/4.cpp @@ -6,9 +6,9 @@ // 教程练习入口: dslings/cpp11/00-auto-and-decltype-4.cpp // -#include +import std; +import d2x; -#include // 4. 类/结构体成员类型推导 @@ -26,21 +26,21 @@ int main() { // obj的类型推导 和 (obj) 的类型推导 type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line // obj.a的类型推导 和 (obj.a) 的类型推导 type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line // obj.b的类型推导 和 (obj.b) 的类型推导 type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line return 0; } diff --git a/solutions/cpp11/00-auto-and-decltype-5.cpp b/solutions/cpp11/00-auto-and-decltype/5.cpp similarity index 72% rename from solutions/cpp11/00-auto-and-decltype-5.cpp rename to solutions/cpp11/00-auto-and-decltype/5.cpp index fe6a5ec..6fcd04c 100644 --- a/solutions/cpp11/00-auto-and-decltype-5.cpp +++ b/solutions/cpp11/00-auto-and-decltype/5.cpp @@ -6,9 +6,9 @@ // 教程练习入口: dslings/cpp11/00-auto-and-decltype-5.cpp // -#include +import std; +import d2x; -#include // 5. const 与引用的剥离和保留 @@ -23,22 +23,22 @@ int main() { // auto 剥离顶层 const: a 推导成 int auto a = ci; type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line // auto 剥离引用: b 推导成 int (b 是 n 的独立副本) auto b = ri; type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line // 用 const auto& 保留 const 引用 const int& const auto& cr = ci; type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line // 用 decltype 精确保留声明类型 const int decltype(ci) d = ci; type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line return 0; } diff --git a/solutions/cpp11/01-default-and-delete-0.cpp b/solutions/cpp11/01-default-and-delete/0.cpp similarity index 93% rename from solutions/cpp11/01-default-and-delete-0.cpp rename to solutions/cpp11/01-default-and-delete/0.cpp index 9e17570..a53f0da 100644 --- a/solutions/cpp11/01-default-and-delete-0.cpp +++ b/solutions/cpp11/01-default-and-delete/0.cpp @@ -6,9 +6,9 @@ // 教程练习入口: dslings/cpp11/01-default-and-delete-0.cpp // -#include +import std; +import d2x; -#include // default和delete显式控制 -> 编译器默认构造函数的生成行为 struct A { }; diff --git a/solutions/cpp11/01-default-and-delete-1.cpp b/solutions/cpp11/01-default-and-delete/1.cpp similarity index 57% rename from solutions/cpp11/01-default-and-delete-1.cpp rename to solutions/cpp11/01-default-and-delete/1.cpp index ea00b86..5c3f520 100644 --- a/solutions/cpp11/01-default-and-delete-1.cpp +++ b/solutions/cpp11/01-default-and-delete/1.cpp @@ -6,9 +6,9 @@ // 教程练习入口: dslings/cpp11/01-default-and-delete-1.cpp // -#include +import std; +import d2x; -#include // 实现std::unique_ptr不可以拷贝, 但可以移动的属性 struct UniquePtr { @@ -26,10 +26,10 @@ int main() { // 不要直接修改main函数中的代码 UniquePtr a; - d2x_assert(std::is_copy_constructible::value == false); - d2x_assert(std::is_copy_assignable::value == false); - d2x_assert(std::is_move_constructible::value == true); - d2x_assert(std::is_move_assignable::value == true); + d2x::check(std::is_copy_constructible::value == false, "std::is_copy_constructible::value == false"); + d2x::check(std::is_copy_assignable::value == false, "std::is_copy_assignable::value == false"); + d2x::check(std::is_move_constructible::value == true, "std::is_move_constructible::value == true"); + d2x::check(std::is_move_assignable::value == true, "std::is_move_assignable::value == true"); (void)a; return 0; diff --git a/solutions/cpp11/01-default-and-delete-2.cpp b/solutions/cpp11/01-default-and-delete/2.cpp similarity index 91% rename from solutions/cpp11/01-default-and-delete-2.cpp rename to solutions/cpp11/01-default-and-delete/2.cpp index d4c5d9a..d2dcf8d 100644 --- a/solutions/cpp11/01-default-and-delete-2.cpp +++ b/solutions/cpp11/01-default-and-delete/2.cpp @@ -6,9 +6,9 @@ // 教程练习入口: dslings/cpp11/01-default-and-delete-2.cpp // -#include +import std; +import d2x; -#include void func(int x) { std::cout << "x = " << x << std::endl; diff --git a/solutions/cpp11/02-final-and-override-0.cpp b/solutions/cpp11/02-final-and-override/0.cpp similarity index 93% rename from solutions/cpp11/02-final-and-override-0.cpp rename to solutions/cpp11/02-final-and-override/0.cpp index d29bb08..22f9237 100644 --- a/solutions/cpp11/02-final-and-override-0.cpp +++ b/solutions/cpp11/02-final-and-override/0.cpp @@ -6,10 +6,9 @@ // 教程练习入口: dslings/cpp11/02-final-and-override-0.cpp // -#include +import std; +import d2x; -#include -#include struct A { virtual void func1() { diff --git a/solutions/cpp11/02-final-and-override-1.cpp b/solutions/cpp11/02-final-and-override/1.cpp similarity index 70% rename from solutions/cpp11/02-final-and-override-1.cpp rename to solutions/cpp11/02-final-and-override/1.cpp index dae19ae..b12f39a 100644 --- a/solutions/cpp11/02-final-and-override-1.cpp +++ b/solutions/cpp11/02-final-and-override/1.cpp @@ -6,10 +6,9 @@ // 教程练习入口: dslings/cpp11/02-final-and-override-1.cpp // -#include +import std; +import d2x; -#include -#include struct A { // 移除 final, 否则 B 不能 override @@ -38,12 +37,12 @@ struct C : B { int main() { B final; // 不要直接修改main函数中的代码 - d2x_assert_eq(final.func1(), 3); // B::func1() - d2x_assert_eq(final.func2(), 4); // B::func2() + d2x::check_eq(final.func1(), 3, "final.func1() == 3"); // B::func1() + d2x::check_eq(final.func2(), 4, "final.func2() == 4"); // B::func2() A *a = &final; - d2x_assert_eq(a->func1(), 3); // B::func1() - d2x_assert_eq(a->func2(), 2); // A::func2() + d2x::check_eq(a->func1(), 3, "a->func1() == 3"); // B::func1() + d2x::check_eq(a->func2(), 2, "a->func2() == 2"); // A::func2() return 0; } diff --git a/solutions/cpp11/02-final-and-override-2.cpp b/solutions/cpp11/02-final-and-override/2.cpp similarity index 96% rename from solutions/cpp11/02-final-and-override-2.cpp rename to solutions/cpp11/02-final-and-override/2.cpp index 360a335..c14ef40 100644 --- a/solutions/cpp11/02-final-and-override-2.cpp +++ b/solutions/cpp11/02-final-and-override/2.cpp @@ -6,10 +6,9 @@ // 教程练习入口: dslings/cpp11/02-final-and-override-2.cpp // -#include +import std; +import d2x; -#include -#include struct AudioPlayer { // 不要直接修改AudioPlayer类 virtual void play() final { diff --git a/solutions/cpp11/03-trailing-return-type.cpp b/solutions/cpp11/03-trailing-return-type/0.cpp similarity index 65% rename from solutions/cpp11/03-trailing-return-type.cpp rename to solutions/cpp11/03-trailing-return-type/0.cpp index bb78e98..c9efef8 100644 --- a/solutions/cpp11/03-trailing-return-type.cpp +++ b/solutions/cpp11/03-trailing-return-type/0.cpp @@ -6,9 +6,9 @@ // 教程练习入口: dslings/cpp11/03-trailing-return-type.cpp // -#include +import std; +import d2x; -#include int add0(double a, int b) { return a + b; @@ -29,11 +29,11 @@ auto add3 = [](double a, double b) -> int { int main() { - d2x_assert_eq(add0(1.1, 2), 3); - d2x_assert_eq(add1(1.1, 2), 3); - d2x_assert_eq(add2(1.1, 2), 3.1); - d2x_assert_eq(add2(1, 2.1), 3.1); - d2x_assert_eq(add3(1.1, 2.1), 3); + d2x::check_eq(add0(1.1, 2), 3, "add0(1.1, 2) == 3"); + d2x::check_eq(add1(1.1, 2), 3, "add1(1.1, 2) == 3"); + d2x::check_eq(add2(1.1, 2), 3.1, "add2(1.1, 2) == 3.1"); + d2x::check_eq(add2(1, 2.1), 3.1, "add2(1, 2.1) == 3.1"); + d2x::check_eq(add3(1.1, 2.1), 3, "add3(1.1, 2.1) == 3"); return 0; } diff --git a/solutions/cpp11/04-rvalue-references.cpp b/solutions/cpp11/04-rvalue-references/0.cpp similarity index 56% rename from solutions/cpp11/04-rvalue-references.cpp rename to solutions/cpp11/04-rvalue-references/0.cpp index 7686923..eefde90 100644 --- a/solutions/cpp11/04-rvalue-references.cpp +++ b/solutions/cpp11/04-rvalue-references/0.cpp @@ -6,13 +6,13 @@ // 教程练习入口: dslings/cpp11/04-rvalue-references.cpp // -#include +import std; +import d2x; -#include -#include struct Object; static Object * object_address = nullptr; +static int move_ctor_calls = 0; // 移动构造被调用的次数, 供断言检查 struct Object { int data = 0; @@ -21,7 +21,7 @@ struct Object { object_address = this; } Object(const Object&) { std::cout << "Object(const Object&):" << this << std::endl; } - Object(Object&&) { std::cout << "Object(Object&&):" << this << std::endl; } + Object(Object&&) { ++move_ctor_calls; std::cout << "Object(Object&&):" << this << std::endl; } ~Object() { std::cout << "~Object():" << this << std::endl; } }; @@ -29,8 +29,13 @@ int main() { // 关闭编译器优化 { std::cout << "----> 临时对像 - 右值1" << std::endl; Object(); - std::cout << "----> 临时对像 - 右值2" << std::endl; - Object obj = Object(); + std::cout << "----> 临时对像 - 右值2(具名对象 + std::move)" << std::endl; + // 注意: 不能写 `Object obj = Object();` 来观察移动构造 —— + // C++17 起 prvalue 直接初始化目标, 保证复制省略, 连 + // -fno-elide-constructors 也无法让那次移动发生。 + // 从具名对象 std::move 才是标准无关的观察方式。 + Object named; + Object obj = std::move(named); (void)obj; std::cout << "--------代码可修改区域-开始--------" << std::endl; @@ -42,7 +47,10 @@ int main() { // 关闭编译器优化 objRef.data = 1; // 修改被延长生命周期的临时对象的值(不要直接改动这行代码) std::cout << "objRef.data = " << objRef.data << " - " << &objRef << std::endl; - d2x_assert((&objRef == object_address)); + d2x::check((&objRef == object_address), "(&objRef == object_address)"); + // 钉住移动构造确实发生过。教学漂移之所以能静默发生, 正是因为 + // 从前没有任何断言检查它 —— 输出少了一行, 没人发现。 + d2x::check((move_ctor_calls >= 1), "(move_ctor_calls >= 1)"); } return 0; diff --git a/solutions/cpp11/05-move-semantics-0.cpp b/solutions/cpp11/05-move-semantics/0.cpp similarity index 85% rename from solutions/cpp11/05-move-semantics-0.cpp rename to solutions/cpp11/05-move-semantics/0.cpp index efb91c6..350bb70 100644 --- a/solutions/cpp11/05-move-semantics-0.cpp +++ b/solutions/cpp11/05-move-semantics/0.cpp @@ -6,11 +6,11 @@ // 教程练习入口: dslings/cpp11/05-move-semantics-0.cpp // // 教学要点: 让 Buffer 在拷贝时也"转移"资源, 只做一次资源分配和释放, -// 这样每个传递点最终都指向同一块缓冲区, 三个 d2x_assert 都通过。 +// 这样每个传递点最终都指向同一块缓冲区, 三个 d2x::check 都通过。 -#include +import std; +import d2x; -#include struct Buffer { int *data; @@ -51,17 +51,17 @@ int main() { Buffer buff2(std::move(buff1)); auto buff2DataPtr = buff2.data_ptr(); - d2x_assert(buff1DataPtr == buff2DataPtr); + d2x::check(buff1DataPtr == buff2DataPtr, "buff1DataPtr == buff2DataPtr"); Buffer buff3 = buff2; auto buff3DataPtr = buff3.data_ptr(); - d2x_assert(buff2DataPtr == buff3DataPtr); + d2x::check(buff2DataPtr == buff3DataPtr, "buff2DataPtr == buff3DataPtr"); Buffer buff4 = process(buff3); auto buff4DataPtr = buff4.data_ptr(); - d2x_assert(buff3DataPtr == buff4DataPtr); + d2x::check(buff3DataPtr == buff4DataPtr, "buff3DataPtr == buff4DataPtr"); } return 0; diff --git a/solutions/cpp11/05-move-semantics-1.cpp b/solutions/cpp11/05-move-semantics/1.cpp similarity index 89% rename from solutions/cpp11/05-move-semantics-1.cpp rename to solutions/cpp11/05-move-semantics/1.cpp index 25d8a25..a8087ee 100644 --- a/solutions/cpp11/05-move-semantics-1.cpp +++ b/solutions/cpp11/05-move-semantics/1.cpp @@ -6,9 +6,9 @@ // 教程练习入口: dslings/cpp11/05-move-semantics-1.cpp // -#include +import std; +import d2x; -#include static int move_assignment_counter = 0; @@ -72,17 +72,17 @@ int main() { // 无编译器优化 buff1 = Buffer(); // 情况1: 临时对象赋值 - d2x_assert_eq(move_assignment_counter, 1); + d2x::check_eq(move_assignment_counter, 1, "move_assignment_counter == 1"); Buffer buff2; buff2 = process(buff1); // 情况2: 中间对象赋值 - d2x_assert_eq(move_assignment_counter, 2); + d2x::check_eq(move_assignment_counter, 2, "move_assignment_counter == 2"); buff2 = std::move(buff1); // 情况3: 显式移动赋值 - d2x_assert_eq(move_assignment_counter, 3); + d2x::check_eq(move_assignment_counter, 3, "move_assignment_counter == 3"); } diff --git a/solutions/cpp11/05-move-semantics-2.cpp b/solutions/cpp11/05-move-semantics/2.cpp similarity index 87% rename from solutions/cpp11/05-move-semantics-2.cpp rename to solutions/cpp11/05-move-semantics/2.cpp index 9521d33..7f1a814 100644 --- a/solutions/cpp11/05-move-semantics-2.cpp +++ b/solutions/cpp11/05-move-semantics/2.cpp @@ -6,9 +6,9 @@ // 教程练习入口: dslings/cpp11/05-move-semantics-2.cpp // -#include +import std; +import d2x; -#include struct Buffer { int *data; @@ -64,9 +64,9 @@ int main() { // 移动语义 - 移动的是资源而不是对象演示 Buffer b2 = std::move(b1); // 触发移动构造 - d2x_assert(&b1 != &b2); // b1 和 b2 是不同的对象 - d2x_assert(old_b1_data_ptr == b2.data_ptr()); - d2x_assert(b1.data_ptr() == nullptr); // b1 的资源被移动了 + d2x::check(&b1 != &b2, "&b1 != &b2"); // b1 和 b2 是不同的对象 + d2x::check(old_b1_data_ptr == b2.data_ptr(), "old_b1_data_ptr == b2.data_ptr()"); + d2x::check(b1.data_ptr() == nullptr, "b1.data_ptr() == nullptr"); // b1 的资源被移动了 } diff --git a/solutions/cpp11/06-scoped-enums-0.cpp b/solutions/cpp11/06-scoped-enums/0.cpp similarity index 89% rename from solutions/cpp11/06-scoped-enums-0.cpp rename to solutions/cpp11/06-scoped-enums/0.cpp index 1085a11..eeae15a 100644 --- a/solutions/cpp11/06-scoped-enums-0.cpp +++ b/solutions/cpp11/06-scoped-enums/0.cpp @@ -8,9 +8,9 @@ // 教学要点: 传统 enum 会污染外层作用域并隐式转 int, 这里通过重命名解决符号冲突, // 保留并展示 "color == Apple" 这种本不该相等却被静默接受的逻辑错误。 -#include +import std; +import d2x; -#include enum Color { RED, @@ -30,8 +30,8 @@ int main() { Color color = RED; Fruit fruit = Apple; - d2x_assert_eq(color, RED); - d2x_assert_eq(fruit, Apple); + d2x::check_eq(color, RED, "color == RED"); + d2x::check_eq(fruit, Apple, "fruit == Apple"); // 2.符合语法, 但逻辑错误的类型匹配 if (color == Apple) { // 不要删除这行代码 diff --git a/solutions/cpp11/06-scoped-enums-1.cpp b/solutions/cpp11/06-scoped-enums/1.cpp similarity index 67% rename from solutions/cpp11/06-scoped-enums-1.cpp rename to solutions/cpp11/06-scoped-enums/1.cpp index 6846e23..2fd050c 100644 --- a/solutions/cpp11/06-scoped-enums-1.cpp +++ b/solutions/cpp11/06-scoped-enums/1.cpp @@ -6,9 +6,9 @@ // 教程练习入口: dslings/cpp11/06-scoped-enums-1.cpp // -#include +import std; +import d2x; -#include enum class Color { RED, @@ -29,12 +29,12 @@ int main() { Color color = Color::ORANGE; Fruit fruit = Fruit::ORANGE; - d2x_assert(color == Color::ORANGE); - d2x_assert(fruit == Fruit::ORANGE); + d2x::check(color == Color::ORANGE, "color == Color::ORANGE"); + d2x::check(fruit == Fruit::ORANGE, "fruit == Fruit::ORANGE"); // 2.类型安全: 防止不同类型的枚举值之间的比较 if (color == Color::ORANGE) { // 使用Color类型修复编译错误 - d2x_assert(color == Color::ORANGE); + d2x::check(color == Color::ORANGE, "color == Color::ORANGE"); } // 3.类型检查: 默认情况下, 范围枚举类型的值是不可隐式转换 @@ -42,15 +42,15 @@ int main() { (void)colorValue; // 4.可自定义底层类型, 控制内存布局 - enum class Color8Bit : int8_t { + enum class Color8Bit : std::int8_t { RED, GREEN, BLUE, ORANGE // 橙色 }; - d2x_assert_eq(sizeof(Color), sizeof(int)); // 默认类型是int - d2x_assert_eq(sizeof(Color8Bit), sizeof(int8_t)); // 可自定义类型int8_t + d2x::check_eq(sizeof(Color), sizeof(int), "sizeof(Color) == sizeof(int)"); // 默认类型是int + d2x::check_eq(sizeof(Color8Bit), sizeof(std::int8_t), "sizeof(Color8Bit) == sizeof(std::int8_t)"); // 可自定义类型int8_t // 5.自定义起始值: 默认情况下, 范围枚举类型的值从0开始, 往下递增 enum class ErrorCode : int { @@ -60,7 +60,7 @@ int main() { ERROR_3 = 3 }; - d2x_assert_eq(static_cast(ErrorCode::ERROR_3), 3); + d2x::check_eq(static_cast(ErrorCode::ERROR_3), 3, "static_cast(ErrorCode::ERROR_3) == 3"); return 0; } diff --git a/solutions/cpp11/07-constexpr-0.cpp b/solutions/cpp11/07-constexpr/0.cpp similarity index 89% rename from solutions/cpp11/07-constexpr-0.cpp rename to solutions/cpp11/07-constexpr/0.cpp index 1085249..068f9bb 100644 --- a/solutions/cpp11/07-constexpr-0.cpp +++ b/solutions/cpp11/07-constexpr/0.cpp @@ -6,9 +6,9 @@ // 教程练习入口: dslings/cpp11/07-constexpr-0.cpp // -#include +import std; +import d2x; -#include constexpr int sum_for_1_to(int n) { return n == 1 ? 1 : n + sum_for_1_to(n - 1); @@ -29,7 +29,7 @@ int main() { { // 2. 编译期计算基础 constexpr int s = sum_for_1_to(4); - d2x_assert_eq(s, 1 + 2 + 3 + 4); + d2x::check_eq(s, 1 + 2 + 3 + 4, "s == 1 + 2 + 3 + 4"); } return 0; diff --git a/solutions/cpp11/07-constexpr-1.cpp b/solutions/cpp11/07-constexpr/1.cpp similarity index 97% rename from solutions/cpp11/07-constexpr-1.cpp rename to solutions/cpp11/07-constexpr/1.cpp index d63a153..28534c5 100644 --- a/solutions/cpp11/07-constexpr-1.cpp +++ b/solutions/cpp11/07-constexpr/1.cpp @@ -6,9 +6,9 @@ // 教程练习入口: dslings/cpp11/07-constexpr-1.cpp // -#include +import std; +import d2x; -#include template struct Sum { diff --git a/solutions/cpp11/08-literal-type-0.cpp b/solutions/cpp11/08-literal-type/0.cpp similarity index 95% rename from solutions/cpp11/08-literal-type-0.cpp rename to solutions/cpp11/08-literal-type/0.cpp index 840d946..50390b4 100644 --- a/solutions/cpp11/08-literal-type-0.cpp +++ b/solutions/cpp11/08-literal-type/0.cpp @@ -9,11 +9,9 @@ // 这里把涉及 std::string 的部分降级为运行时, 其余字面值类型 (char/int/std::array) // 仍可参与编译期计算。 -#include +import std; +import d2x; -#include -#include -#include constexpr char compile_time_compute(char c, int a) { return a + c; diff --git a/solutions/cpp11/08-literal-type-1.cpp b/solutions/cpp11/08-literal-type/1.cpp similarity index 92% rename from solutions/cpp11/08-literal-type-1.cpp rename to solutions/cpp11/08-literal-type/1.cpp index 264f0cb..068ee4f 100644 --- a/solutions/cpp11/08-literal-type-1.cpp +++ b/solutions/cpp11/08-literal-type/1.cpp @@ -6,9 +6,9 @@ // 教程练习入口: dslings/cpp11/08-literal-type-1.cpp // -#include +import std; +import d2x; -#include struct Vector { int x, y; diff --git a/solutions/cpp11/09-list-initialization-0.cpp b/solutions/cpp11/09-list-initialization/0.cpp similarity index 68% rename from solutions/cpp11/09-list-initialization-0.cpp rename to solutions/cpp11/09-list-initialization/0.cpp index c96bf57..6607e39 100644 --- a/solutions/cpp11/09-list-initialization-0.cpp +++ b/solutions/cpp11/09-list-initialization/0.cpp @@ -7,19 +7,19 @@ // // 教学要点: 大括号(列表)初始化对窄化转换不允许, 需要使用显式 static_cast 修复。 -#include +import std; +import d2x; -#include int main() { int a1 = 1.1; // 拷贝初始化允许窄化, 截断为 1 - d2x_assert_eq(a1, 1); + d2x::check_eq(a1, 1, "a1 == 1"); int a2 = 1.1; int a3 = { static_cast(1.1) }; // 大括号初始化要求显式转换 - d2x_assert_eq(a2, 1); - d2x_assert_eq(a3, 1); + d2x::check_eq(a2, 1, "a2 == 1"); + d2x::check_eq(a3, 1, "a3 == 1"); double b1 { 1.1 }; constexpr double c1 { 2.2 }; @@ -27,16 +27,16 @@ int main() { int b2 { static_cast(b1) }; int c2 { static_cast(c1) }; - d2x_assert_eq(b2, 1); - d2x_assert_eq(c2, 2); + d2x::check_eq(b2, 1, "b2 == 1"); + d2x::check_eq(c2, 2, "c2 == 2"); int arr1[] = { 1, static_cast(2.2), 3 }; - d2x_assert_eq(arr1[1], 2); + d2x::check_eq(arr1[1], 2, "arr1[1] == 2"); int arr2[4] { 1, static_cast(b1), static_cast(c1) }; - d2x_assert_eq(arr2[1], 1); - d2x_assert_eq(arr2[2], 2); - d2x_assert_eq(arr2[3], 0); + d2x::check_eq(arr2[1], 1, "arr2[1] == 1"); + d2x::check_eq(arr2[2], 2, "arr2[2] == 2"); + d2x::check_eq(arr2[3], 0, "arr2[3] == 0"); return 0; } diff --git a/solutions/cpp11/09-list-initialization-1.cpp b/solutions/cpp11/09-list-initialization/1.cpp similarity index 85% rename from solutions/cpp11/09-list-initialization-1.cpp rename to solutions/cpp11/09-list-initialization/1.cpp index d470863..e9416f2 100644 --- a/solutions/cpp11/09-list-initialization-1.cpp +++ b/solutions/cpp11/09-list-initialization/1.cpp @@ -6,9 +6,9 @@ // 教程练习入口: dslings/cpp11/09-list-initialization-1.cpp // -#include +import std; +import d2x; -#include struct Object { Object() { @@ -28,8 +28,8 @@ int main() { Object obj1{}; Object obj2(2); - d2x_assert_eq(obj1.x, 0); - d2x_assert_eq(obj2.x, 2); + d2x::check_eq(obj1.x, 0, "obj1.x == 0"); + d2x::check_eq(obj2.x, 2, "obj2.x == 2"); return 0; } diff --git a/solutions/cpp11/09-list-initialization-2.cpp b/solutions/cpp11/09-list-initialization/2.cpp similarity index 72% rename from solutions/cpp11/09-list-initialization-2.cpp rename to solutions/cpp11/09-list-initialization/2.cpp index f87f9f1..666622a 100644 --- a/solutions/cpp11/09-list-initialization-2.cpp +++ b/solutions/cpp11/09-list-initialization/2.cpp @@ -6,11 +6,9 @@ // 教程练习入口: dslings/cpp11/09-list-initialization-2.cpp // -#include +import std; +import d2x; -#include -#include -#include class MyVector { int mSize; @@ -26,14 +24,14 @@ class MyVector { int main() { std::vector vec1 = { 1, 2, 3 }; - d2x_assert_eq(vec1.size(), 3); + d2x::check_eq(vec1.size(), 3, "vec1.size() == 3"); std::vector vec2 { 1, 2, 3, 4, 5 }; - d2x_assert_eq(vec2.size(), 5); + d2x::check_eq(vec2.size(), 5, "vec2.size() == 5"); MyVector myVec1 = { 1, 2, 3 }; - d2x_assert_eq(myVec1.size(), 3); + d2x::check_eq(myVec1.size(), 3, "myVec1.size() == 3"); MyVector myVec2 { 1, 2, 3, 4, 5 }; - d2x_assert_eq(myVec2.size(), 5); + d2x::check_eq(myVec2.size(), 5, "myVec2.size() == 5"); return 0; } diff --git a/solutions/cpp11/09-list-initialization-3.cpp b/solutions/cpp11/09-list-initialization/3.cpp similarity index 86% rename from solutions/cpp11/09-list-initialization-3.cpp rename to solutions/cpp11/09-list-initialization/3.cpp index 4872fde..fe1f294 100644 --- a/solutions/cpp11/09-list-initialization-3.cpp +++ b/solutions/cpp11/09-list-initialization/3.cpp @@ -11,10 +11,9 @@ // 2. 列表初始化优先选 std::initializer_list 重载, 这里去掉 initializer_list 重载, // 让 `MyVector vec4 { 1, 10 }` 命中 (int, int) 构造函数。 -#include +import std; +import d2x; -#include -#include class MyVector { int mSize; @@ -63,14 +62,14 @@ int main() { (void)p1; (void)p2; MyVector vec1(1); - d2x_assert_eq(vec1.size(), 1); + d2x::check_eq(vec1.size(), 1, "vec1.size() == 1"); MyVector vec2 { 1 }; - d2x_assert_eq(vec2.size(), 1); + d2x::check_eq(vec2.size(), 1, "vec2.size() == 1"); MyVector vec3(1, 10); - d2x_assert_eq(vec3.size(), 10); + d2x::check_eq(vec3.size(), 10, "vec3.size() == 10"); MyVector vec4 { 1, 10 }; - d2x_assert_eq(vec4.size(), 10); + d2x::check_eq(vec4.size(), 10, "vec4.size() == 10"); return 0; } diff --git a/solutions/cpp11/10-delegating-constructors-0.cpp b/solutions/cpp11/10-delegating-constructors/0.cpp similarity index 74% rename from solutions/cpp11/10-delegating-constructors-0.cpp rename to solutions/cpp11/10-delegating-constructors/0.cpp index 81ae70a..634d17b 100644 --- a/solutions/cpp11/10-delegating-constructors-0.cpp +++ b/solutions/cpp11/10-delegating-constructors/0.cpp @@ -9,10 +9,9 @@ // 既复用初始化逻辑, 又使每次构造仅按链路上每个构造函数体各 ++ 一次, // 计数器 1->3->5->6 与断言匹配。 -#include +import std; +import d2x; -#include -#include static int construction_counter { 0 }; @@ -26,28 +25,28 @@ class Account { Account(std::string id_) : Account(id_, "momo") { - D2X_DONT_DELETE_THIS(construction_counter++); + d2x::dont_delete_this(construction_counter++); } // 2 参 -> 委托给 3 参版本, 自身体再增加一次计数 (a2: +2) Account(std::string id_, std::string name_) : Account(id_, name_, 0) { - D2X_DONT_DELETE_THIS(construction_counter++); + d2x::dont_delete_this(construction_counter++); } // 3 参 -> 真正初始化的"基础版本" (a3: +1) Account(std::string id_, std::string name_, int coin_) { id = id_; name = name_; - // 满足最后一个 d2x_assert: GImpact 角色 coin 后缀使用 "原石" + // 满足最后一个 d2x::check: GImpact 角色 coin 后缀使用 "原石" if (name == "GImpact") { coin = std::to_string(coin_) + "原石"; } else { coin = std::to_string(coin_) + "元"; } - D2X_DONT_DELETE_THIS(construction_counter++); + d2x::dont_delete_this(construction_counter++); } std::string to_string() const { @@ -58,24 +57,22 @@ class Account { int main() { // 不要修改main函数中的代码 Account a1 { "1111" }; - d2x_assert_eq(construction_counter, 3); + d2x::check_eq(construction_counter, 3, "construction_counter == 3"); std::cout << a1.to_string() << std::endl; Account a2 { "2222", "wukong" }; - d2x_assert_eq(construction_counter, 5); + d2x::check_eq(construction_counter, 5, "construction_counter == 5"); std::cout << a2.to_string() << std::endl; Account a3 { "3333", "mcpp", 100 }; - d2x_assert_eq(construction_counter, 6); + d2x::check_eq(construction_counter, 6, "construction_counter == 6"); std::cout << a3.to_string() << std::endl; Account gi { "0000", "GImpact", 648 }; std::cout << gi.to_string() << std::endl; - d2x_assert( - gi.to_string() == - "Account { id: 0000, name: GImpact, coin: 648原石 }" - ); + d2x::check(gi.to_string() == + "Account { id: 0000, name: GImpact, coin: 648原石 }", "gi.to_string() == \"Account { id: 0000, name: GImpact, coin: 648原石 }\""); return 0; } diff --git a/solutions/cpp11/10-delegating-constructors-1.cpp b/solutions/cpp11/10-delegating-constructors/1.cpp similarity index 89% rename from solutions/cpp11/10-delegating-constructors-1.cpp rename to solutions/cpp11/10-delegating-constructors/1.cpp index 21306c6..a78680c 100644 --- a/solutions/cpp11/10-delegating-constructors-1.cpp +++ b/solutions/cpp11/10-delegating-constructors/1.cpp @@ -11,10 +11,9 @@ // `: Account(id_, name_, 0) {}` 才是真正的委托。 // 3. 用成员初始化列表直接构造 obj, 避免多余的默认构造 + 移动赋值, 让计数 == 1. -#include +import std; +import d2x; -#include -#include struct Object { // 不要修改这个类的代码 static int construction_counter; @@ -76,14 +75,14 @@ int main() { // 不要修改main函数中的代码 Account a1 { "1111", "hello" }; std::cout << a1.to_string() << std::endl; - d2x_assert(a1.get_id() == "1111"); + d2x::check(a1.get_id() == "1111", "a1.get_id() == \"1111\""); Object::construction_counter = 0; Account a2 { "2222", "d2learn", 100 }; std::cout << a2.to_string() << std::endl; - d2x_assert(a2.get_object_name() == "d2learn"); - d2x_assert_eq(Object::construction_counter, 1); + d2x::check(a2.get_object_name() == "d2learn", "a2.get_object_name() == \"d2learn\""); + d2x::check_eq(Object::construction_counter, 1, "Object::construction_counter == 1"); return 0; } diff --git a/solutions/cpp11/11-inherited-constructors-0.cpp b/solutions/cpp11/11-inherited-constructors/0.cpp similarity index 96% rename from solutions/cpp11/11-inherited-constructors-0.cpp rename to solutions/cpp11/11-inherited-constructors/0.cpp index 77d28e5..ec3d236 100644 --- a/solutions/cpp11/11-inherited-constructors-0.cpp +++ b/solutions/cpp11/11-inherited-constructors/0.cpp @@ -6,10 +6,9 @@ // 教程练习入口: dslings/cpp11/11-inherited-constructors-0.cpp // -#include +import std; +import d2x; -#include -#include class ObjectBase { public: diff --git a/solutions/cpp11/11-inherited-constructors-1.cpp b/solutions/cpp11/11-inherited-constructors/1.cpp similarity index 63% rename from solutions/cpp11/11-inherited-constructors-1.cpp rename to solutions/cpp11/11-inherited-constructors/1.cpp index 62cd51a..6ea1de7 100644 --- a/solutions/cpp11/11-inherited-constructors-1.cpp +++ b/solutions/cpp11/11-inherited-constructors/1.cpp @@ -6,10 +6,9 @@ // 教程练习入口: dslings/cpp11/11-inherited-constructors-1.cpp // -#include +import std; +import d2x; -#include -#include class Student { // 不要直接修改 Student 类中的代码 protected: @@ -61,31 +60,31 @@ int main() { // 不要直接修改 main 函数中的代码 { // 基础测试 StudentTest studentTest; - d2x_assert(studentTest.age_valid() == true); - d2x_assert(studentTest.score_valid() == true); - d2x_assert(studentTest.to_string() == "{001, 张三, 18, 0}"); + d2x::check(studentTest.age_valid() == true, "studentTest.age_valid() == true"); + d2x::check(studentTest.score_valid() == true, "studentTest.score_valid() == true"); + d2x::check(studentTest.to_string() == "{001, 张三, 18, 0}", "studentTest.to_string() == \"{001, 张三, 18, 0}\""); } { // 边界测试 StudentTest studentTest("002", "张三", 201); - d2x_assert(studentTest.score_valid() == true); - d2x_assert(studentTest.age_valid() == false); + d2x::check(studentTest.score_valid() == true, "studentTest.score_valid() == true"); + d2x::check(studentTest.age_valid() == false, "studentTest.age_valid() == false"); studentTest.set_score(101); studentTest.set_age(200); - d2x_assert(studentTest.score_valid() == false); - d2x_assert(studentTest.age_valid() == true); + d2x::check(studentTest.score_valid() == false, "studentTest.score_valid() == false"); + d2x::check(studentTest.age_valid() == true, "studentTest.age_valid() == true"); studentTest.set_score(0); studentTest.set_age(1); - d2x_assert(studentTest.score_valid() == true); - d2x_assert(studentTest.age_valid() == true); + d2x::check(studentTest.score_valid() == true, "studentTest.score_valid() == true"); + d2x::check(studentTest.age_valid() == true, "studentTest.age_valid() == true"); studentTest.set_score(-1); studentTest.set_age(0); - d2x_assert(studentTest.score_valid() == false); - d2x_assert(studentTest.age_valid() == false); + d2x::check(studentTest.score_valid() == false, "studentTest.score_valid() == false"); + d2x::check(studentTest.age_valid() == false, "studentTest.age_valid() == false"); } diff --git a/solutions/cpp11/11-inherited-constructors-2.cpp b/solutions/cpp11/11-inherited-constructors/2.cpp similarity index 84% rename from solutions/cpp11/11-inherited-constructors-2.cpp rename to solutions/cpp11/11-inherited-constructors/2.cpp index 8af159a..6d73f64 100644 --- a/solutions/cpp11/11-inherited-constructors-2.cpp +++ b/solutions/cpp11/11-inherited-constructors/2.cpp @@ -8,10 +8,9 @@ // 教学要点: NoMove 的拷贝控制只声明 = default 的拷贝构造/拷贝赋值, 不显式声明 // 移动操作 -> 移动操作不会被隐式生成, `std::move(p3)` 会回退到拷贝. -#include +import std; +import d2x; -#include -#include struct Point { double mX, mY; @@ -56,13 +55,13 @@ int main() { auto p11 = p1; std::cout << "p11: " << p11.to_string() << std::endl; - d2x_assert_eq(p1.mX, p11.mX); - d2x_assert_eq(p1.mY, p11.mY); + d2x::check_eq(p1.mX, p11.mX, "p1.mX == p11.mX"); + d2x::check_eq(p1.mY, p11.mY, "p1.mY == p11.mY"); decltype(p2) p22 = std::move(p2); // NoCopy 不能拷贝, 只能 move std::cout << "p22: " << p22.to_string() << std::endl; - d2x_assert_eq(p2.mX, p22.mX); - d2x_assert_eq(p2.mY, p22.mY); + d2x::check_eq(p2.mX, p22.mX, "p2.mX == p22.mX"); + d2x::check_eq(p2.mY, p22.mY, "p2.mY == p22.mY"); NoMove p3(3, 3); std::cout << "p3: " << p3.to_string() << std::endl; @@ -70,8 +69,8 @@ int main() { NoMove p33(0, 0); p33 = std::move(p3); // NoMove 没有 move 重载, 回退到拷贝赋值 std::cout << "p33: " << p33.to_string() << std::endl; - d2x_assert_eq(p3.mX, p33.mX); - d2x_assert_eq(p3.mY, p33.mY); + d2x::check_eq(p3.mX, p33.mX, "p3.mX == p33.mX"); + d2x::check_eq(p3.mY, p33.mY, "p3.mY == p33.mY"); return 0; } diff --git a/solutions/cpp11/12-nullptr-0.cpp b/solutions/cpp11/12-nullptr/0.cpp similarity index 63% rename from solutions/cpp11/12-nullptr-0.cpp rename to solutions/cpp11/12-nullptr/0.cpp index efd31ee..1e38352 100644 --- a/solutions/cpp11/12-nullptr-0.cpp +++ b/solutions/cpp11/12-nullptr/0.cpp @@ -6,10 +6,10 @@ // 教程练习入口: dslings/cpp11/12-nullptr-0.cpp // -#include +#include // NULL 宏是这一课的教具,import std 不带宏 +import std; +import d2x; -#include -#include int main() { @@ -18,13 +18,13 @@ int main() { int* ptr2 = NULL; // 修复这里,添加正确类型 int* ptr3 = 0; // 不推荐的传统用法 - d2x_assert(ptr1 == nullptr); - d2x_assert(ptr2 == nullptr); - d2x_assert(ptr3 == nullptr); + d2x::check(ptr1 == nullptr, "ptr1 == nullptr"); + d2x::check(ptr2 == nullptr, "ptr2 == nullptr"); + d2x::check(ptr3 == nullptr, "ptr3 == nullptr"); // 2. nullptr的类型 bool ok = std::is_same::value; - d2x_assert(ok); + d2x::check(ok, "ok"); // 3. 使用 nullptr 进行指针比较 int value = 42; @@ -32,7 +32,7 @@ int main() { if (ptr4 != nullptr) { *ptr4 = 2233; - d2x_assert_eq(*ptr4, 2233); + d2x::check_eq(*ptr4, 2233, "*ptr4 == 2233"); } // 4. 不同类型的指针都可以使用 nullptr @@ -40,9 +40,9 @@ int main() { char* cptr = nullptr; void* vptr = nullptr; - d2x_assert(dptr == nullptr); - d2x_assert(cptr == nullptr); - d2x_assert(vptr == nullptr); + d2x::check(dptr == nullptr, "dptr == nullptr"); + d2x::check(cptr == nullptr, "cptr == nullptr"); + d2x::check(vptr == nullptr, "vptr == nullptr"); return 0; } diff --git a/solutions/cpp11/12-nullptr-1.cpp b/solutions/cpp11/12-nullptr/1.cpp similarity index 78% rename from solutions/cpp11/12-nullptr-1.cpp rename to solutions/cpp11/12-nullptr/1.cpp index b2d9bb9..e9c6525 100644 --- a/solutions/cpp11/12-nullptr-1.cpp +++ b/solutions/cpp11/12-nullptr/1.cpp @@ -6,7 +6,8 @@ // 教程练习入口: dslings/cpp11/12-nullptr-1.cpp // -#include +import std; +import d2x; bool process_int_called = false; bool process_ptr_called = false; @@ -40,10 +41,10 @@ int main() { display(nullptr); // 用 nullptr 准确选中 display(int*) process(0); // -> process(int) - d2x_assert(process_int_called); - d2x_assert(display_int_called); - d2x_assert(display_ptr_called); - d2x_assert(display_ptr_called); + d2x::check(process_int_called, "process_int_called"); + d2x::check(display_int_called, "display_int_called"); + d2x::check(display_ptr_called, "display_ptr_called"); + d2x::check(display_ptr_called, "display_ptr_called"); return 0; } diff --git a/solutions/cpp11/12-nullptr-2.cpp b/solutions/cpp11/12-nullptr/2.cpp similarity index 90% rename from solutions/cpp11/12-nullptr-2.cpp rename to solutions/cpp11/12-nullptr/2.cpp index 4906bac..f508072 100644 --- a/solutions/cpp11/12-nullptr-2.cpp +++ b/solutions/cpp11/12-nullptr/2.cpp @@ -6,8 +6,9 @@ // 教程练习入口: dslings/cpp11/12-nullptr-2.cpp // -#include -#include +#include // NULL 宏是这一课的教具,import std 不带宏 +import std; +import d2x; // 模板函数示例 template diff --git a/solutions/cpp11/13-long-long-0.cpp b/solutions/cpp11/13-long-long/0.cpp similarity index 78% rename from solutions/cpp11/13-long-long-0.cpp rename to solutions/cpp11/13-long-long/0.cpp index 0b55006..ac0a6ad 100644 --- a/solutions/cpp11/13-long-long-0.cpp +++ b/solutions/cpp11/13-long-long/0.cpp @@ -6,9 +6,9 @@ // 教程练习入口: dslings/cpp11/13-long-long-0.cpp // -#include +import std; +import d2x; -#include int main() { @@ -19,7 +19,7 @@ int main() { // 2. 整数表示范围(unsigned int 装不下,需要 unsigned long long) unsigned long long uVal1 = 18446744073709551615ULL; - d2x_assert_eq(uVal1, 18446744073709551615ULL); + d2x::check_eq(uVal1, 18446744073709551615ULL, "uVal1 == 18446744073709551615ULL"); // 3. 类型推导和字面量后缀 auto longlong = 1234567890LL; @@ -28,8 +28,8 @@ int main() { bool is_longlong = std::is_same::value; bool is_ulonglong = std::is_same::value; - d2x_assert(is_longlong == true); - d2x_assert(is_ulonglong == true); + d2x::check(is_longlong == true, "is_longlong == true"); + d2x::check(is_ulonglong == true, "is_ulonglong == true"); return 0; } diff --git a/solutions/cpp11/13-long-long-1.cpp b/solutions/cpp11/13-long-long/1.cpp similarity index 62% rename from solutions/cpp11/13-long-long-1.cpp rename to solutions/cpp11/13-long-long/1.cpp index ca95734..1c0fc55 100644 --- a/solutions/cpp11/13-long-long-1.cpp +++ b/solutions/cpp11/13-long-long/1.cpp @@ -6,9 +6,9 @@ // 教程练习入口: dslings/cpp11/13-long-long-1.cpp // -#include +import std; +import d2x; -#include int main() { @@ -18,14 +18,14 @@ int main() { auto minLL = std::numeric_limits::min(); auto maxULL = std::numeric_limits::max(); - d2x_assert_eq(maxInt, 2147483647); - d2x_assert_eq(maxLL, 9223372036854775807LL); - d2x_assert_eq(minLL, -9223372036854775807LL - 1); - d2x_assert_eq(maxULL, 18446744073709551615ULL); + d2x::check_eq(maxInt, 2147483647, "maxInt == 2147483647"); + d2x::check_eq(maxLL, 9223372036854775807LL, "maxLL == 9223372036854775807LL"); + d2x::check_eq(minLL, -9223372036854775807LL - 1, "minLL == -9223372036854775807LL - 1"); + d2x::check_eq(maxULL, 18446744073709551615ULL, "maxULL == 18446744073709551615ULL"); // 2. 大整数应用 - 表示世界人口(int 装不下 7.8e9) unsigned long long currentPopulation = 7800000000ULL; - d2x_assert_eq(currentPopulation, 7800000000ULL); + d2x::check_eq(currentPopulation, 7800000000ULL, "currentPopulation == 7800000000ULL"); return 0; } diff --git a/solutions/cpp11/14-type-alias-0.cpp b/solutions/cpp11/14-type-alias/0.cpp similarity index 68% rename from solutions/cpp11/14-type-alias-0.cpp rename to solutions/cpp11/14-type-alias/0.cpp index 9c045c8..98efc7c 100644 --- a/solutions/cpp11/14-type-alias-0.cpp +++ b/solutions/cpp11/14-type-alias/0.cpp @@ -6,9 +6,9 @@ // 教程练习入口: dslings/cpp11/14-type-alias-0.cpp // -#include +import std; +import d2x; -#include int main() { @@ -16,22 +16,22 @@ int main() { using Integer = int; using Real = double; - bool ok = std::is_same::value; d2x_assert(ok); - ok = std::is_same::value; d2x_assert(ok); + bool ok = std::is_same::value; d2x::check(ok, "ok"); + ok = std::is_same::value; d2x::check(ok, "ok"); // 2. 使用类型别名 Integer a = 42; Real b = 3.14; // 3. 验证类型别名 - d2x_assert_eq(a, 42); - d2x_assert_eq(b, 3.14); + d2x::check_eq(a, 42, "a == 42"); + d2x::check_eq(b, 3.14, "b == 3.14"); // 4. 类型别名本质相同 int c = 100; Integer d = c; // 可以赋值,因为本质都是int - d2x_assert_eq(c, d); + d2x::check_eq(c, d, "c == d"); return 0; } diff --git a/solutions/cpp11/14-type-alias-1.cpp b/solutions/cpp11/14-type-alias/1.cpp similarity index 76% rename from solutions/cpp11/14-type-alias-1.cpp rename to solutions/cpp11/14-type-alias/1.cpp index 2082868..51a91fb 100644 --- a/solutions/cpp11/14-type-alias-1.cpp +++ b/solutions/cpp11/14-type-alias/1.cpp @@ -6,10 +6,9 @@ // 教程练习入口: dslings/cpp11/14-type-alias-1.cpp // -#include +import std; +import d2x; -#include -#include static int func_called = 0; @@ -26,7 +25,7 @@ int main() { FuncPtr func = example_func; func(1, 2); - d2x_assert_eq(func_called, 3); + d2x::check_eq(func_called, 3, "func_called == 3"); // 2. 容器类型别名 using StringVector = std::vector; @@ -42,9 +41,9 @@ int main() { Container::ValueType value = 100; // 4. 验证类型别名 - d2x_assert(strings[0] == "hello"); - d2x_assert(strings[1] == "world"); - d2x_assert_eq(value, 100); + d2x::check(strings[0] == "hello", "strings[0] == \"hello\""); + d2x::check(strings[1] == "world", "strings[1] == \"world\""); + d2x::check_eq(value, 100, "value == 100"); return 0; } diff --git a/solutions/cpp11/14-type-alias-2.cpp b/solutions/cpp11/14-type-alias/2.cpp similarity index 69% rename from solutions/cpp11/14-type-alias-2.cpp rename to solutions/cpp11/14-type-alias/2.cpp index 586db61..1a660b5 100644 --- a/solutions/cpp11/14-type-alias-2.cpp +++ b/solutions/cpp11/14-type-alias/2.cpp @@ -6,12 +6,9 @@ // 教程练习入口: dslings/cpp11/14-type-alias-2.cpp // -#include +import std; +import d2x; -#include -#include -#include -#include // 1. 基本别名模板 template @@ -32,13 +29,13 @@ int main() { Heap minHeap; (void)minHeap; - d2x_assert_eq(numbers[0], 1); - d2x_assert_eq(numbers[1], 2); - d2x_assert_eq(numbers[2], 3); + d2x::check_eq(numbers[0], 1, "numbers[0] == 1"); + d2x::check_eq(numbers[1], 2, "numbers[1] == 2"); + d2x::check_eq(numbers[2], 3, "numbers[2] == 3"); - d2x_assert_eq(v3[0], 1.0f); - d2x_assert_eq(v3[1], 2.0f); - d2x_assert_eq(v3[2], 3.0f); + d2x::check_eq(v3[0], 1.0f, "v3[0] == 1.0f"); + d2x::check_eq(v3[1], 2.0f, "v3[1] == 2.0f"); + d2x::check_eq(v3[2], 3.0f, "v3[2] == 3.0f"); return 0; } diff --git a/solutions/cpp11/14-type-alias-3.cpp b/solutions/cpp11/14-type-alias/3.cpp similarity index 85% rename from solutions/cpp11/14-type-alias-3.cpp rename to solutions/cpp11/14-type-alias/3.cpp index dc83708..c1e16f6 100644 --- a/solutions/cpp11/14-type-alias-3.cpp +++ b/solutions/cpp11/14-type-alias/3.cpp @@ -6,8 +6,8 @@ // 教程练习入口: dslings/cpp11/14-type-alias-3.cpp // -#include -#include +import std; +import d2x; // 别名模板必须定义在命名空间作用域(不能写在函数体内) template @@ -20,8 +20,8 @@ int main() { bool ok = std::is_same, int*>::value; - d2x_assert(ok); - d2x_assert_eq(*ptr, 20); + d2x::check(ok, "ok"); + d2x::check_eq(*ptr, 20, "*ptr == 20"); return 0; } diff --git a/solutions/cpp11/15-variadic-templates-0.cpp b/solutions/cpp11/15-variadic-templates/0.cpp similarity index 87% rename from solutions/cpp11/15-variadic-templates-0.cpp rename to solutions/cpp11/15-variadic-templates/0.cpp index fe8a8c1..ba2a48d 100644 --- a/solutions/cpp11/15-variadic-templates-0.cpp +++ b/solutions/cpp11/15-variadic-templates/0.cpp @@ -6,8 +6,8 @@ // 教程练习入口: dslings/cpp11/15-variadic-templates-0.cpp // -#include -#include +import std; +import d2x; std::stringstream ss; @@ -26,7 +26,7 @@ int main() { print(1, "hello", 3.14); std::string result = ss.str(); - d2x_assert(result == "1 hello 3.14 "); + d2x::check(result == "1 hello 3.14 ", "result == \"1 hello 3.14 \""); return 0; } diff --git a/solutions/cpp11/15-variadic-templates-1.cpp b/solutions/cpp11/15-variadic-templates/1.cpp similarity index 81% rename from solutions/cpp11/15-variadic-templates-1.cpp rename to solutions/cpp11/15-variadic-templates/1.cpp index ab75026..b1035b6 100644 --- a/solutions/cpp11/15-variadic-templates-1.cpp +++ b/solutions/cpp11/15-variadic-templates/1.cpp @@ -6,7 +6,8 @@ // 教程练习入口: dslings/cpp11/15-variadic-templates-1.cpp // -#include +import std; +import d2x; // 递归终止: 只剩一个参数时直接返回 template @@ -19,15 +20,15 @@ T sum(T first, Args... args) { int main() { int res1 = sum(1, 2, 3, 4, 5); - d2x_assert_eq(res1, 15); + d2x::check_eq(res1, 15, "res1 == 15"); double res2 = sum(1.5, 2.5, 3.0); - d2x_assert(res2 == 7.0); + d2x::check(res2 == 7.0, "res2 == 7.0"); // 混合类型 // 注意: 返回类型由第一个参数 T 决定 int res3 = sum(10, 20.5); - d2x_assert_eq(res3, 30); + d2x::check_eq(res3, 30, "res3 == 30"); return 0; } diff --git a/solutions/cpp11/16-generalized-unions-0.cpp b/solutions/cpp11/16-generalized-unions/0.cpp similarity index 88% rename from solutions/cpp11/16-generalized-unions-0.cpp rename to solutions/cpp11/16-generalized-unions/0.cpp index 72f36b1..11680de 100644 --- a/solutions/cpp11/16-generalized-unions-0.cpp +++ b/solutions/cpp11/16-generalized-unions/0.cpp @@ -6,7 +6,8 @@ // 教程练习入口: dslings/cpp11/16-generalized-unions-0.cpp // -#include +import std; +import d2x; union M @@ -22,7 +23,7 @@ int main() { M u1; //初始化成员 - d2x_assert(u1.a1 == 42); + d2x::check(u1.a1 == 42, "u1.a1 == 42"); u1.a2 = 21; double val = 3.14; diff --git a/solutions/cpp11/16-generalized-unions-1.cpp b/solutions/cpp11/16-generalized-unions/1.cpp similarity index 88% rename from solutions/cpp11/16-generalized-unions-1.cpp rename to solutions/cpp11/16-generalized-unions/1.cpp index 7fc63e3..a417409 100644 --- a/solutions/cpp11/16-generalized-unions-1.cpp +++ b/solutions/cpp11/16-generalized-unions/1.cpp @@ -6,8 +6,8 @@ // 教程练习入口: dslings/cpp11/16-generalized-unions-1.cpp // -#include -#include +import std; +import d2x; union M { @@ -31,7 +31,7 @@ int main() { u1.a2 = {1, 42, 3}; // 2. 验证:正常访问 - d2x_assert_eq(u1.a2[1], 42); + d2x::check_eq(u1.a2[1], 42, "u1.a2[1] == 42"); // 3. 手动析构 u1.a2.~vector(); diff --git a/solutions/cpp11/16-generalized-unions-2.cpp b/solutions/cpp11/16-generalized-unions/2.cpp similarity index 75% rename from solutions/cpp11/16-generalized-unions-2.cpp rename to solutions/cpp11/16-generalized-unions/2.cpp index 4f4a067..c42c62b 100644 --- a/solutions/cpp11/16-generalized-unions-2.cpp +++ b/solutions/cpp11/16-generalized-unions/2.cpp @@ -6,9 +6,8 @@ // 教程练习入口: dslings/cpp11/16-generalized-unions-2.cpp // -#include -#include -#include +import std; +import d2x; enum class Tag { INTEGER, @@ -55,25 +54,25 @@ int main() { // 1. 构造 int 值并验证 Value v1(42); - d2x_assert(v1.tag == Tag::INTEGER); - d2x_assert_eq(v1.as_int(), 42); + d2x::check(v1.tag == Tag::INTEGER, "v1.tag == Tag::INTEGER"); + d2x::check_eq(v1.as_int(), 42, "v1.as_int() == 42"); // 2. 构造 string 值并验证 Value v2(std::string("hello")); - d2x_assert(v2.tag == Tag::STRING); - d2x_assert(v2.as_string() == "hello"); + d2x::check(v2.tag == Tag::STRING, "v2.tag == Tag::STRING"); + d2x::check(v2.as_string() == "hello", "v2.as_string() == \"hello\""); // 3. 从 string 切换到 int { Value v3(std::string("world")); - d2x_assert(v3.as_string() == "world"); + d2x::check(v3.as_string() == "world", "v3.as_string() == \"world\""); // 手动析构 string 成员, 切换到 int v3.data.s.~basic_string(); v3.tag = Tag::INTEGER; v3.data.i = 100; - d2x_assert_eq(v3.as_int(), 100); + d2x::check_eq(v3.as_int(), 100, "v3.as_int() == 100"); // 离开作用域时 ~Value() 发现 tag == INTEGER, 不析构 string } diff --git a/solutions/cpp11/17-pod-type-0.cpp b/solutions/cpp11/17-pod-type/0.cpp similarity index 90% rename from solutions/cpp11/17-pod-type-0.cpp rename to solutions/cpp11/17-pod-type/0.cpp index 58330f4..d51a7d3 100644 --- a/solutions/cpp11/17-pod-type-0.cpp +++ b/solutions/cpp11/17-pod-type/0.cpp @@ -6,9 +6,9 @@ // 教程练习入口: dslings/cpp11/17-pod-type-0.cpp // -#include +import std; +import d2x; -#include struct A { int x; @@ -40,17 +40,17 @@ int main() { // 3. 判断 A 是否是 trivial /standard_layout 类型 bool ok = std::is_trivial::value && std::is_standard_layout::value; - d2x_assert(ok); + d2x::check(ok, "ok"); // 4. 判断 B 是否是 trivial /standard_layout 类型 ok = std::is_trivial::value && std::is_standard_layout::value; - d2x_assert(ok); + d2x::check(ok, "ok"); // 5. C 含虚函数 -> 不是 trivial 类型 (assert 期望条件成立, 因此用否定) ok = !std::is_trivial::value; - d2x_assert(ok); + d2x::check(ok, "ok"); // 6. D 同时含 public/private 数据 -> 不是 standard_layout ok = std::is_standard_layout::value; - d2x_assert(!ok); + d2x::check(!ok, "!ok"); } diff --git a/solutions/cpp11/17-pod-type-1.cpp b/solutions/cpp11/17-pod-type/1.cpp similarity index 67% rename from solutions/cpp11/17-pod-type-1.cpp rename to solutions/cpp11/17-pod-type/1.cpp index da5d9e3..ead5c5e 100644 --- a/solutions/cpp11/17-pod-type-1.cpp +++ b/solutions/cpp11/17-pod-type/1.cpp @@ -6,10 +6,9 @@ // 教程练习入口: dslings/cpp11/17-pod-type-1.cpp // -#include +import std; +import d2x; -#include -#include struct Packet { @@ -29,9 +28,9 @@ int main() { // 使用 memcpy 在 POD 上做按字节拷贝 std::memcpy(&p2, &p1, sizeof(Packet)); - d2x_assert_eq(p2.len, 42u); - d2x_assert_eq(p2.type, static_cast(1)); - d2x_assert_eq(p2.flags, static_cast(0xFF)); + d2x::check_eq(p2.len, 42u, "p2.len == 42u"); + d2x::check_eq(p2.type, static_cast(1), "p2.type == static_cast(1)"); + d2x::check_eq(p2.flags, static_cast(0xFF), "p2.flags == static_cast(0xFF)"); return 0; } diff --git a/solutions/cpp11/17-pod-type-2.cpp b/solutions/cpp11/17-pod-type/2.cpp similarity index 74% rename from solutions/cpp11/17-pod-type-2.cpp rename to solutions/cpp11/17-pod-type/2.cpp index 457550d..ba90193 100644 --- a/solutions/cpp11/17-pod-type-2.cpp +++ b/solutions/cpp11/17-pod-type/2.cpp @@ -6,10 +6,9 @@ // 教程练习入口: dslings/cpp11/17-pod-type-2.cpp // -#include +import std; +import d2x; -#include -#include // C 风格的消息头部,仅包含 POD 成员,用于跨语言/跨模块传递 @@ -29,7 +28,7 @@ struct Message { static MessageHeader g_last_header{}; extern "C" void c_send_header(const void* data, std::size_t size) { - d2x_assert_eq(size, sizeof(MessageHeader)); + d2x::check_eq(size, sizeof(MessageHeader), "size == sizeof(MessageHeader)"); const auto* header = static_cast(data); g_last_header = *header; } @@ -50,9 +49,9 @@ int main() { send_message_to_c(msg); // 验证 C 接口收到的头部内容是否正确 - d2x_assert_eq(g_last_header.type, msg.type); - d2x_assert_eq(g_last_header.len, static_cast(msg.payload.size())); - d2x_assert_eq(g_last_header.flags, static_cast(0)); + d2x::check_eq(g_last_header.type, msg.type, "g_last_header.type == msg.type"); + d2x::check_eq(g_last_header.len, static_cast(msg.payload.size()), "g_last_header.len == static_cast(msg.payload.size())"); + d2x::check_eq(g_last_header.flags, static_cast(0), "g_last_header.flags == static_cast(0)"); return 0; } diff --git a/solutions/cpp11/xmake.lua b/solutions/cpp11/xmake.lua deleted file mode 100644 index 31cdd51..0000000 --- a/solutions/cpp11/xmake.lua +++ /dev/null @@ -1,198 +0,0 @@ --- Reference solutions for cpp11 chapter exercises. --- Each target name mirrors dslings/cpp11/ with a "-ref" suffix. --- Used by CI to verify exercise infrastructure (xmake target / include paths / --- language standard) and that the canonical answer actually passes all --- d2x_assert / d2x_assert_eq checks. - -if is_host("windows") then - set_languages("cxx14") -else - set_languages("cxx11") -end - --- target: cpp11-00-auto-and-decltype - -target("cpp11-00-auto-and-decltype-0-ref") - add_files("00-auto-and-decltype-0.cpp") - -target("cpp11-00-auto-and-decltype-1-ref") - add_files("00-auto-and-decltype-1.cpp") - -target("cpp11-00-auto-and-decltype-2-ref") - add_files("00-auto-and-decltype-2.cpp") - -target("cpp11-00-auto-and-decltype-3-ref") - add_files("00-auto-and-decltype-3.cpp") - -target("cpp11-00-auto-and-decltype-4-ref") - add_files("00-auto-and-decltype-4.cpp") - -target("cpp11-00-auto-and-decltype-5-ref") - add_files("00-auto-and-decltype-5.cpp") - --- target: cpp11-01-default-and-delete - -target("cpp11-01-default-and-delete-0-ref") - add_files("01-default-and-delete-0.cpp") - -target("cpp11-01-default-and-delete-1-ref") - add_files("01-default-and-delete-1.cpp") - -target("cpp11-01-default-and-delete-2-ref") - add_files("01-default-and-delete-2.cpp") - --- target: cpp11-02-final-and-override - -target("cpp11-02-final-and-override-0-ref") - add_files("02-final-and-override-0.cpp") - -target("cpp11-02-final-and-override-1-ref") - add_files("02-final-and-override-1.cpp") - -target("cpp11-02-final-and-override-2-ref") - add_files("02-final-and-override-2.cpp") - --- target: cpp11-03-trailing-return-type - -target("cpp11-03-trailing-return-type-ref") - add_files("03-trailing-return-type.cpp") - --- target: cpp11-04-rvalue-references - -target("cpp11-04-rvalue-references-ref") - set_optimize("none") - add_cxxflags("-fno-elide-constructors") - add_files("04-rvalue-references.cpp") - --- target: cpp11-05-move-semantics - -target("cpp11-05-move-semantics-0-ref") - add_files("05-move-semantics-0.cpp") - -target("cpp11-05-move-semantics-1-ref") - add_files("05-move-semantics-1.cpp") - -target("cpp11-05-move-semantics-2-ref") - add_files("05-move-semantics-2.cpp") - --- target: cpp11-06-scoped-enums - -target("cpp11-06-scoped-enums-0-ref") - add_files("06-scoped-enums-0.cpp") - -target("cpp11-06-scoped-enums-1-ref") - add_files("06-scoped-enums-1.cpp") - --- target: cpp11-07-constexpr - -target("cpp11-07-constexpr-0-ref") - add_cxxflags("-Wpedantic -Werror") - add_files("07-constexpr-0.cpp") - -target("cpp11-07-constexpr-1-ref") - add_files("07-constexpr-1.cpp") - --- target: cpp11-08-literal-type - -target("cpp11-08-literal-type-0-ref") - set_languages("c++17") -- TODO: optimize it - add_files("08-literal-type-0.cpp") - -target("cpp11-08-literal-type-1-ref") - add_files("08-literal-type-1.cpp") - --- target: cpp11-09-list-initialization - -target("cpp11-09-list-initialization-0-ref") - add_files("09-list-initialization-0.cpp") - -target("cpp11-09-list-initialization-1-ref") - add_files("09-list-initialization-1.cpp") - -target("cpp11-09-list-initialization-2-ref") - add_files("09-list-initialization-2.cpp") - -target("cpp11-09-list-initialization-3-ref") - add_files("09-list-initialization-3.cpp") - --- target: cpp11-10-delegating-constructors - -target("cpp11-10-delegating-constructors-0-ref") - add_files("10-delegating-constructors-0.cpp") - -target("cpp11-10-delegating-constructors-1-ref") - add_files("10-delegating-constructors-1.cpp") - --- target: cpp11-11-inherited-constructors - -target("cpp11-11-inherited-constructors-0-ref") - add_files("11-inherited-constructors-0.cpp") - -target("cpp11-11-inherited-constructors-1-ref") - add_files("11-inherited-constructors-1.cpp") - -target("cpp11-11-inherited-constructors-2-ref") - add_files("11-inherited-constructors-2.cpp") - --- target: cpp11-12-nullptr - -target("cpp11-12-nullptr-0-ref") - add_files("12-nullptr-0.cpp") - -target("cpp11-12-nullptr-1-ref") - add_files("12-nullptr-1.cpp") - -target("cpp11-12-nullptr-2-ref") - add_files("12-nullptr-2.cpp") - --- target: cpp11-13-long-long - -target("cpp11-13-long-long-0-ref") - add_files("13-long-long-0.cpp") - -target("cpp11-13-long-long-1-ref") - add_files("13-long-long-1.cpp") - --- target: cpp11-14-type-alias - -target("cpp11-14-type-alias-0-ref") - add_files("14-type-alias-0.cpp") - -target("cpp11-14-type-alias-1-ref") - add_files("14-type-alias-1.cpp") - -target("cpp11-14-type-alias-2-ref") - add_files("14-type-alias-2.cpp") - -target("cpp11-14-type-alias-3-ref") - add_files("14-type-alias-3.cpp") - --- target: cpp11-15-variadic-templates - -target("cpp11-15-variadic-templates-0-ref") - add_files("15-variadic-templates-0.cpp") - -target("cpp11-15-variadic-templates-1-ref") - add_files("15-variadic-templates-1.cpp") - --- target: cpp11-16-generalized-unions - -target("cpp11-16-generalized-unions-0-ref") - add_files("16-generalized-unions-0.cpp") - -target("cpp11-16-generalized-unions-1-ref") - add_files("16-generalized-unions-1.cpp") - -target("cpp11-16-generalized-unions-2-ref") - add_files("16-generalized-unions-2.cpp") - --- target: cpp11-17-pod-type - -target("cpp11-17-pod-type-0-ref") - add_files("17-pod-type-0.cpp") - -target("cpp11-17-pod-type-1-ref") - add_files("17-pod-type-1.cpp") - -target("cpp11-17-pod-type-2-ref") - add_files("17-pod-type-2.cpp") diff --git a/solutions/cpp14/00-generic-lambdas-0.cpp b/solutions/cpp14/00-generic-lambdas-0.cpp deleted file mode 100644 index 473711b..0000000 --- a/solutions/cpp14/00-generic-lambdas-0.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// d2mcpp: https://github.com/mcpp-community/d2mcpp -// license: Apache-2.0 -// reference solution for: dslings/cpp14/00-generic-lambdas-0.cpp -// -// 用途: 仅给 CI 与维护者参考使用,不是教程入口。 -// 教程练习入口: dslings/cpp14/00-generic-lambdas-0.cpp -// - -#include -#include - -int main() { - - // 0. 简单泛型 lambda — identity - auto identity = [](auto x) { - return x; - }; - - d2x_assert_eq(identity(42), 42); - d2x_assert(identity(std::string("hello")) == "hello"); - d2x_assert_eq(identity(3.14), 3.14); - - // 1. 泛型 lambda 做比较 - auto greater = [](auto a, auto b) { - return a > b; - }; - - d2x_assert(greater(5, 3)); - d2x_assert(greater(2.5, 1.2)); - d2x_assert(greater(std::string("z"), std::string("a"))); - - // 2. 推导类型确认 - auto get_type_size = [](auto x) { - return sizeof(x); - }; - - d2x_assert_eq(get_type_size(42), sizeof(int)); - d2x_assert_eq(get_type_size('c'), sizeof(char)); - - return 0; -} diff --git a/solutions/cpp14/00-generic-lambdas/0.cpp b/solutions/cpp14/00-generic-lambdas/0.cpp new file mode 100644 index 0000000..a199b79 --- /dev/null +++ b/solutions/cpp14/00-generic-lambdas/0.cpp @@ -0,0 +1,41 @@ +// d2mcpp: https://github.com/mcpp-community/d2mcpp +// license: Apache-2.0 +// reference solution for: dslings/cpp14/00-generic-lambdas-0.cpp +// +// 用途: 仅给 CI 与维护者参考使用,不是教程入口。 +// 教程练习入口: dslings/cpp14/00-generic-lambdas-0.cpp +// + +import std; +import d2x; + +int main() { + + // 0. 简单泛型 lambda — identity + auto identity = [](auto x) { + return x; + }; + + d2x::check_eq(identity(42), 42, "identity(42) == 42"); + d2x::check(identity(std::string("hello")) == "hello", "identity(std::string(\"hello\")) == \"hello\""); + d2x::check_eq(identity(3.14), 3.14, "identity(3.14) == 3.14"); + + // 1. 泛型 lambda 做比较 + auto greater = [](auto a, auto b) { + return a > b; + }; + + d2x::check(greater(5, 3), "greater(5, 3)"); + d2x::check(greater(2.5, 1.2), "greater(2.5, 1.2)"); + d2x::check(greater(std::string("z"), std::string("a")), "greater(std::string(\"z\"), std::string(\"a\"))"); + + // 2. 推导类型确认 + auto get_type_size = [](auto x) { + return sizeof(x); + }; + + d2x::check_eq(get_type_size(42), sizeof(int), "get_type_size(42) == sizeof(int)"); + d2x::check_eq(get_type_size('c'), sizeof(char), "get_type_size('c') == sizeof(char)"); + + return 0; +} diff --git a/solutions/cpp14/00-generic-lambdas-1.cpp b/solutions/cpp14/00-generic-lambdas/1.cpp similarity index 75% rename from solutions/cpp14/00-generic-lambdas-1.cpp rename to solutions/cpp14/00-generic-lambdas/1.cpp index c977d7d..72c8713 100644 --- a/solutions/cpp14/00-generic-lambdas-1.cpp +++ b/solutions/cpp14/00-generic-lambdas/1.cpp @@ -6,9 +6,8 @@ // 教程练习入口: dslings/cpp14/00-generic-lambdas-1.cpp // -#include -#include -#include +import std; +import d2x; int main() { @@ -21,11 +20,11 @@ int main() { }; std::sort(v1.begin(), v1.end(), desc); - d2x_assert_eq(v1[0], 8); - d2x_assert_eq(v1[4], 1); + d2x::check_eq(v1[0], 8, "v1[0] == 8"); + d2x::check_eq(v1[4], 1, "v1[4] == 1"); std::sort(v2.begin(), v2.end(), desc); - d2x_assert_eq(v2[0], 8.5); + d2x::check_eq(v2[0], 8.5, "v2[0] == 8.5"); // 1. 带捕获的泛型 lambda — find_if int threshold = 3; @@ -34,10 +33,10 @@ int main() { }; auto it1 = std::find_if(v1.begin(), v1.end(), above); - d2x_assert(*it1 == 8); + d2x::check(*it1 == 8, "*it1 == 8"); auto it2 = std::find_if(v2.begin(), v2.end(), above); - d2x_assert(*it2 == 8.5); + d2x::check(*it2 == 8.5, "*it2 == 8.5"); // 2. 泛型 lambda 返回 lambda — 函数工厂 auto make_multiplier = [](auto factor) { @@ -45,8 +44,8 @@ int main() { }; auto times2 = make_multiplier(2); - d2x_assert_eq(times2(10), 20); - d2x_assert_eq(times2(0.5), 1.0); + d2x::check_eq(times2(10), 20, "times2(10) == 20"); + d2x::check_eq(times2(0.5), 1.0, "times2(0.5) == 1.0"); return 0; } diff --git a/solutions/cpp14/xmake.lua b/solutions/cpp14/xmake.lua deleted file mode 100644 index 8bbbb90..0000000 --- a/solutions/cpp14/xmake.lua +++ /dev/null @@ -1,11 +0,0 @@ -set_languages("cxx14") - --- target: cpp14-00-generic-lambdas - -target("cpp14-00-generic-lambdas-0-ref") - set_kind("binary") - add_files("00-generic-lambdas-0.cpp") - -target("cpp14-00-generic-lambdas-1-ref") - set_kind("binary") - add_files("00-generic-lambdas-1.cpp") diff --git a/solutions/intro/hello-mcpp.cpp b/solutions/intro/hello-mcpp.cpp new file mode 100644 index 0000000..41340ac --- /dev/null +++ b/solutions/intro/hello-mcpp.cpp @@ -0,0 +1,21 @@ +// d2mcpp: https://github.com/mcpp-community/d2mcpp +// license: Apache-2.0 +// file: src/intro/tests/hello-mcpp.cpp (参考答案) + +import std; +import d2x; + +int main() { + + std::cout << "hello, mcpp!" << std::endl; // 0.修复这个编译错误 + + double a = 1.1; // 1.修复这个运行时错误, 修改int为double, 通过检查 + + d2x::check_eq(a, 1.1, "a == 1.1"); // 2.运行时检查点, 需要修复代码通过所有检查点(不能直接删除检查点代码) + + int b = a; // 3.修复这个编译错误, 给b一个合适的类型(int 截断 1.1 -> 1) + + d2x::check_eq(b, 1, "b == 1"); // 4.运行时检查点2 + + return 0; +} diff --git a/solutions/xmake.lua b/solutions/xmake.lua deleted file mode 100644 index c1b845e..0000000 --- a/solutions/xmake.lua +++ /dev/null @@ -1,11 +0,0 @@ --- Reference solutions root. --- Mirrors dslings/ structure but only contains the canonical "filled-in" --- answers, used purely for build / run CI. Each target carries the "-ref" --- suffix to coexist with the dslings/ targets that share the same logical --- name (e.g. cpp11-13-long-long-0 vs cpp11-13-long-long-0-ref). --- --- Solutions are language-neutral by design: the comments matter only to --- contributors, not the compiler, so we keep a single zh-style copy. - -includes("cpp11/xmake.lua") -includes("cpp14/xmake.lua") diff --git a/src/cpp11/mcpp.toml b/src/cpp11/mcpp.toml new file mode 100644 index 0000000..8c12878 --- /dev/null +++ b/src/cpp11/mcpp.toml @@ -0,0 +1,10 @@ +# cpp11 练习工程。练习 = tests/<章节>/<序号>.cpp,由 mcpp test 直接驱动: +# mcpp test -p src/cpp11 全部练习(进度表) +# mcpp test -p src/cpp11 <子串> 只跑匹配的练习 +[package] +name = "cpp11" +version = "0.1.0" +standard = "c++23" + +[dependencies] +d2x = { path = "../../d2x" } diff --git a/dslings/cpp11/00-auto-and-decltype-0.cpp b/src/cpp11/tests/00-auto-and-decltype/0.cpp similarity index 74% rename from dslings/cpp11/00-auto-and-decltype-0.cpp rename to src/cpp11/tests/00-auto-and-decltype/0.cpp index 3e8e3a4..d00cf0a 100644 --- a/dslings/cpp11/00-auto-and-decltype-0.cpp +++ b/src/cpp11/tests/00-auto-and-decltype/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/00-auto-and-decltype-0.cpp +// file: src/cpp11/tests/00-auto-and-decltype/0.cpp // // Exercise/练习: cpp11 | 00 - auto and decltype | 自动类型推导 // @@ -18,7 +18,8 @@ // d2x checker auto-and-decltype // -#include +import std; +import d2x; int main() { @@ -35,14 +36,13 @@ int main() { D2X_YOUR_ANSWER c1 = c; D2X_YOUR_ANSWER c2 = c; - d2x_assert_eq(a, a1); - d2x_assert_eq(a1, a2); - d2x_assert_eq(b, b1); - d2x_assert_eq(b1, b2); - d2x_assert_eq(c, c1); - d2x_assert_eq(c1, c2); - - D2X_WAIT + d2x::check_eq(a, a1, "a == a1"); + d2x::check_eq(a1, a2, "a1 == a2"); + d2x::check_eq(b, b1, "b == b1"); + d2x::check_eq(b1, b2, "b1 == b2"); + d2x::check_eq(c, c1, "c == c1"); + d2x::check_eq(c1, c2, "c1 == c2"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/00-auto-and-decltype-1.cpp b/src/cpp11/tests/00-auto-and-decltype/1.cpp similarity index 75% rename from dslings/cpp11/00-auto-and-decltype-1.cpp rename to src/cpp11/tests/00-auto-and-decltype/1.cpp index 29d76f9..47da877 100644 --- a/dslings/cpp11/00-auto-and-decltype-1.cpp +++ b/src/cpp11/tests/00-auto-and-decltype/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/00-auto-and-decltype-1.cpp +// file: src/cpp11/tests/00-auto-and-decltype/1.cpp // // Exercise/练习: cpp11 | 00 - auto and decltype | 表达式类型推导 // @@ -19,7 +19,8 @@ // -#include +import std; +import d2x; int main() { @@ -36,12 +37,11 @@ int main() { D2X_YOUR_ANSWER c1 = 1 + c; D2X_YOUR_ANSWER c2 = 2 + 'a'; - d2x_assert_eq(a2, a + 2 + 1.1); - d2x_assert_eq(b1, a + 0.1); - d2x_assert_eq(c1, 1 + c); - d2x_assert_eq(c2, 2 + 'a'); - - D2X_WAIT + d2x::check_eq(a2, a + 2 + 1.1, "a2 == a + 2 + 1.1"); + d2x::check_eq(b1, a + 0.1, "b1 == a + 0.1"); + d2x::check_eq(c1, 1 + c, "c1 == 1 + c"); + d2x::check_eq(c2, 2 + 'a', "c2 == 2 + 'a'"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/00-auto-and-decltype-2.cpp b/src/cpp11/tests/00-auto-and-decltype/2.cpp similarity index 84% rename from dslings/cpp11/00-auto-and-decltype-2.cpp rename to src/cpp11/tests/00-auto-and-decltype/2.cpp index 8b3fa4c..4350995 100644 --- a/dslings/cpp11/00-auto-and-decltype-2.cpp +++ b/src/cpp11/tests/00-auto-and-decltype/2.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/00-auto-and-decltype-2.cpp +// file: src/cpp11/tests/00-auto-and-decltype/2.cpp // // Exercise/练习: cpp11 | 00 - auto and decltype | 复杂类型推导 // @@ -18,11 +18,9 @@ // d2x checker auto-and-decltype-2 // -#include +import std; +import d2x; -#include -#include -#include int add_func(int a, int b) { return a + b; @@ -53,10 +51,9 @@ int main() { minus_func }; - d2x_assert_eq(funcVec[0](1, 2), 3); - d2x_assert_eq(funcVec[1](1, 2), -1); - - D2X_WAIT + d2x::check_eq(funcVec[0](1, 2), 3, "funcVec[0](1, 2) == 3"); + d2x::check_eq(funcVec[1](1, 2), -1, "funcVec[1](1, 2) == -1"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/00-auto-and-decltype-3.cpp b/src/cpp11/tests/00-auto-and-decltype/3.cpp similarity index 74% rename from dslings/cpp11/00-auto-and-decltype-3.cpp rename to src/cpp11/tests/00-auto-and-decltype/3.cpp index a75fc96..81fddc4 100644 --- a/dslings/cpp11/00-auto-and-decltype-3.cpp +++ b/src/cpp11/tests/00-auto-and-decltype/3.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/00-auto-and-decltype-3.cpp +// file: src/cpp11/tests/00-auto-and-decltype/3.cpp // // Exercise/练习: cpp11 | 00 - auto and decltype | 函数返回值类型推导 // @@ -18,10 +18,9 @@ // d2x checker auto-and-decltype-3 // -#include +import std; +import d2x; -#include -#include // 3. 函数返回值类型 @@ -36,11 +35,10 @@ D2X_YOUR_ANSWER minus_func(T1 a, T2 b) -> D2X_YOUR_ANSWER { int main() { - d2x_assert_eq(minus_func(1, 2), -1); - d2x_assert_eq(minus_func(2, 1), 1); - d2x_assert_eq(minus_func(1, 2.1), -1.1); - - D2X_WAIT + d2x::check_eq(minus_func(1, 2), -1, "minus_func(1, 2) == -1"); + d2x::check_eq(minus_func(2, 1), 1, "minus_func(2, 1) == 1"); + d2x::check_eq(minus_func(1, 2.1), -1.1, "minus_func(1, 2.1) == -1.1"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/00-auto-and-decltype-4.cpp b/src/cpp11/tests/00-auto-and-decltype/4.cpp similarity index 70% rename from dslings/cpp11/00-auto-and-decltype-4.cpp rename to src/cpp11/tests/00-auto-and-decltype/4.cpp index aadb47f..239a417 100644 --- a/dslings/cpp11/00-auto-and-decltype-4.cpp +++ b/src/cpp11/tests/00-auto-and-decltype/4.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/00-auto-and-decltype-4.cpp +// file: src/cpp11/tests/00-auto-and-decltype/4.cpp // // Exercise/练习: cpp11 | 00 - auto and decltype | 类/结构体成员类型推导 // @@ -18,9 +18,9 @@ // d2x checker auto-and-decltype-4 // -#include +import std; +import d2x; -#include // 4. 类/结构体成员类型推导 @@ -38,23 +38,22 @@ int main() { // obj的类型推导 和 (obj) 的类型推导 type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line // obj.a的类型推导 和 (obj.a) 的类型推导 type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line // obj.b的类型推导 和 (obj.b) 的类型推导 type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line - - D2X_WAIT + d2x::check(type_check, "type_check"); type_check = false; // dont change this line + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/00-auto-and-decltype-5.cpp b/src/cpp11/tests/00-auto-and-decltype/5.cpp similarity index 76% rename from dslings/cpp11/00-auto-and-decltype-5.cpp rename to src/cpp11/tests/00-auto-and-decltype/5.cpp index 0cd35bd..3bca5ba 100644 --- a/dslings/cpp11/00-auto-and-decltype-5.cpp +++ b/src/cpp11/tests/00-auto-and-decltype/5.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/00-auto-and-decltype-5.cpp +// file: src/cpp11/tests/00-auto-and-decltype/5.cpp // // Exercise/练习: cpp11 | 00 - auto and decltype | const 与引用的剥离和保留 // @@ -18,9 +18,9 @@ // d2x checker auto-and-decltype-5 // -#include +import std; +import d2x; -#include // 5. const 与引用的剥离和保留 @@ -35,24 +35,23 @@ int main() { // auto 剥离顶层 const: a 推导成什么? auto a = ci; type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line // auto 剥离引用: b 推导成什么?(b 是 n 的独立副本) auto b = ri; type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line // 想保留 const 引用 const int&: cr 该怎么声明? D2X_YOUR_ANSWER cr = ci; type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line // 想精确保留声明类型 const int: d 该怎么声明? D2X_YOUR_ANSWER d = ci; type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line - - D2X_WAIT + d2x::check(type_check, "type_check"); type_check = false; // dont change this line + d2x::wait(); return 0; } diff --git a/dslings/cpp11/01-default-and-delete-0.cpp b/src/cpp11/tests/01-default-and-delete/0.cpp similarity index 88% rename from dslings/cpp11/01-default-and-delete-0.cpp rename to src/cpp11/tests/01-default-and-delete/0.cpp index 63d45da..ae892af 100644 --- a/dslings/cpp11/01-default-and-delete-0.cpp +++ b/src/cpp11/tests/01-default-and-delete/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/01-default-and-delete-0.cpp +// file: src/cpp11/tests/01-default-and-delete/0.cpp // // Exercise/练习: cpp11 | 01 - default and delete | 显示指定构造函数生成行为 // @@ -15,9 +15,9 @@ // d2x checker default-and-delete // -#include +import std; +import d2x; -#include // default和delete显式控制 -> 编译器默认构造函数的生成行为 struct A { }; @@ -35,7 +35,6 @@ int main() { // 不要直接修改main函数中的代码 B b; C c(1); - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/01-default-and-delete-1.cpp b/src/cpp11/tests/01-default-and-delete/1.cpp similarity index 62% rename from dslings/cpp11/01-default-and-delete-1.cpp rename to src/cpp11/tests/01-default-and-delete/1.cpp index a0b4e58..c269dc6 100644 --- a/dslings/cpp11/01-default-and-delete-1.cpp +++ b/src/cpp11/tests/01-default-and-delete/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/01-default-and-delete-1.cpp +// file: src/cpp11/tests/01-default-and-delete/1.cpp // // Exercise/练习: cpp11 | 01 - default and delete | 不可拷贝对像 // @@ -15,9 +15,9 @@ // d2x checker default-and-delete-1 // -#include +import std; +import d2x; -#include // 实现std::unique_ptr不可以拷贝, 但可以移动的属性 struct UniquePtr { @@ -32,17 +32,16 @@ int main() { // 不要直接修改main函数中的代码 // 对像不可拷贝/复制 // std::unique_ptr b = a; // error - d2x_assert(std::is_copy_constructible::value == false); + d2x::check(std::is_copy_constructible::value == false, "std::is_copy_constructible::value == false"); // a = b; // error - d2x_assert(std::is_copy_assignable::value == false); + d2x::check(std::is_copy_assignable::value == false, "std::is_copy_assignable::value == false"); // 对像可移动 // std::unique_ptr c = std::move(a); // ok - d2x_assert(std::is_move_constructible::value == true); + d2x::check(std::is_move_constructible::value == true, "std::is_move_constructible::value == true"); // a = std::move(c); // ok - d2x_assert(std::is_move_assignable::value == true); - - D2X_WAIT + d2x::check(std::is_move_assignable::value == true, "std::is_move_assignable::value == true"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/01-default-and-delete-2.cpp b/src/cpp11/tests/01-default-and-delete/2.cpp similarity index 85% rename from dslings/cpp11/01-default-and-delete-2.cpp rename to src/cpp11/tests/01-default-and-delete/2.cpp index 7f57468..800294c 100644 --- a/dslings/cpp11/01-default-and-delete-2.cpp +++ b/src/cpp11/tests/01-default-and-delete/2.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/01-default-and-delete-2.cpp +// file: src/cpp11/tests/01-default-and-delete/2.cpp // // Exercise/练习: cpp11 | 01 - default and delete | 禁止函数重载 // @@ -15,9 +15,9 @@ // d2x checker default-and-delete-2 // -#include +import std; +import d2x; -#include void func(int x) { std::cout << "x = " << x << std::endl; @@ -31,7 +31,6 @@ int main() { func(1); // int func(1.1f); // float - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/02-final-and-override-0.cpp b/src/cpp11/tests/02-final-and-override/0.cpp similarity index 88% rename from dslings/cpp11/02-final-and-override-0.cpp rename to src/cpp11/tests/02-final-and-override/0.cpp index f676de1..f702ddd 100644 --- a/dslings/cpp11/02-final-and-override-0.cpp +++ b/src/cpp11/tests/02-final-and-override/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/02-final-and-override-0.cpp +// file: src/cpp11/tests/02-final-and-override/0.cpp // // Exercise/练习: cpp11 | 02 - final and override // @@ -15,10 +15,9 @@ // d2x checker final-and-override // -#include +import std; +import d2x; -#include -#include struct A { virtual void func1() { @@ -51,7 +50,6 @@ int main() { a->func1(); // B::func1() a->func2(); // A::func2() - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/02-final-and-override-1.cpp b/src/cpp11/tests/02-final-and-override/1.cpp similarity index 66% rename from dslings/cpp11/02-final-and-override-1.cpp rename to src/cpp11/tests/02-final-and-override/1.cpp index 104b886..175357e 100644 --- a/dslings/cpp11/02-final-and-override-1.cpp +++ b/src/cpp11/tests/02-final-and-override/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/02-final-and-override-1.cpp +// file: src/cpp11/tests/02-final-and-override/1.cpp // // Exercise/练习: cpp11 | 02 - final and override // @@ -15,10 +15,9 @@ // d2x checker final-and-override-1 // -#include +import std; +import d2x; -#include -#include struct A { virtual int func1() final { @@ -45,14 +44,13 @@ struct C : B { int main() { B final; // 不要直接修改main函数中的代码 - d2x_assert_eq(final.func1(), 3); // B::func1() - d2x_assert_eq(final.func2(), 4); // B::func2() + d2x::check_eq(final.func1(), 3, "final.func1() == 3"); // B::func1() + d2x::check_eq(final.func2(), 4, "final.func2() == 4"); // B::func2() A *a = &final; - d2x_assert_eq(a->func1(), 3); // B::func1() - d2x_assert_eq(a->func2(), 2); // A::func2() - - D2X_WAIT + d2x::check_eq(a->func1(), 3, "a->func1() == 3"); // B::func1() + d2x::check_eq(a->func2(), 2, "a->func2() == 2"); // A::func2() + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/02-final-and-override-2.cpp b/src/cpp11/tests/02-final-and-override/2.cpp similarity index 93% rename from dslings/cpp11/02-final-and-override-2.cpp rename to src/cpp11/tests/02-final-and-override/2.cpp index 51f08da..9652bc0 100644 --- a/dslings/cpp11/02-final-and-override-2.cpp +++ b/src/cpp11/tests/02-final-and-override/2.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/02-final-and-override-2.cpp +// file: src/cpp11/tests/02-final-and-override/2.cpp // // Exercise/练习: cpp11 | 02 - final and override // @@ -15,10 +15,9 @@ // d2x checker final-and-override-2 // -#include +import std; +import d2x; -#include -#include struct AudioPlayer { // 不要直接修改AudioPlayer类 virtual void play() final { @@ -77,7 +76,6 @@ int main() { // 不要直接修改main函数中的代码 delete player2; delete player3; - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/03-trailing-return-type.cpp b/src/cpp11/tests/03-trailing-return-type/0.cpp similarity index 64% rename from dslings/cpp11/03-trailing-return-type.cpp rename to src/cpp11/tests/03-trailing-return-type/0.cpp index 06c0c46..4aee4cc 100644 --- a/dslings/cpp11/03-trailing-return-type.cpp +++ b/src/cpp11/tests/03-trailing-return-type/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/03-trailing-return-type.cpp +// file: src/cpp11/tests/03-trailing-return-type/0.cpp // // Exercise/练习: cpp11 | 03 - trailing return type // @@ -14,9 +14,9 @@ // d2x checker trailing-return-type // -#include +import std; +import d2x; -#include int add0(double a, int b) { return a + b; @@ -37,13 +37,12 @@ auto add3 = [](double a, double b) -> D2X_YOUR_ANSWER { int main() { - d2x_assert_eq(add0(1.1, 2), 3); - d2x_assert_eq(add1(1.1, 2), 3); - d2x_assert_eq(add2(1.1, 2), 3.1); - d2x_assert_eq(add2(1, 2.1), 3.1); - d2x_assert_eq(add3(1.1, 2.1), 3); - - D2X_WAIT + d2x::check_eq(add0(1.1, 2), 3, "add0(1.1, 2) == 3"); + d2x::check_eq(add1(1.1, 2), 3, "add1(1.1, 2) == 3"); + d2x::check_eq(add2(1.1, 2), 3.1, "add2(1.1, 2) == 3.1"); + d2x::check_eq(add2(1, 2.1), 3.1, "add2(1, 2.1) == 3.1"); + d2x::check_eq(add3(1.1, 2.1), 3, "add3(1.1, 2.1) == 3"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/04-rvalue-references.cpp b/src/cpp11/tests/04-rvalue-references/0.cpp similarity index 55% rename from dslings/cpp11/04-rvalue-references.cpp rename to src/cpp11/tests/04-rvalue-references/0.cpp index 83660b2..ee7cadc 100644 --- a/dslings/cpp11/04-rvalue-references.cpp +++ b/src/cpp11/tests/04-rvalue-references/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/04-rvalue-references.cpp +// file: src/cpp11/tests/04-rvalue-references/0.cpp // // Exercise/练习: cpp11 | 04 - rvalue references // @@ -14,13 +14,13 @@ // d2x checker rvalue-references // -#include +import std; +import d2x; -#include -#include struct Object; static Object * object_address = nullptr; +static int move_ctor_calls = 0; // 移动构造被调用的次数, 供断言检查 struct Object { int data = 0; @@ -29,7 +29,7 @@ struct Object { object_address = this; } Object(const Object&) { std::cout << "Object(const Object&):" << this << std::endl; } - Object(Object&&) { std::cout << "Object(Object&&):" << this << std::endl; } + Object(Object&&) { ++move_ctor_calls; std::cout << "Object(Object&&):" << this << std::endl; } ~Object() { std::cout << "~Object():" << this << std::endl; } }; @@ -37,8 +37,13 @@ int main() { // 关闭编译器优化 { std::cout << "----> 临时对像 - 右值1" << std::endl; Object(); - std::cout << "----> 临时对像 - 右值2" << std::endl; - Object obj = Object(); + std::cout << "----> 临时对像 - 右值2(具名对象 + std::move)" << std::endl; + // 注意: 不能写 `Object obj = Object();` 来观察移动构造 —— + // C++17 起 prvalue 直接初始化目标, 保证复制省略, 连 + // -fno-elide-constructors 也无法让那次移动发生。 + // 从具名对象 std::move 才是标准无关的观察方式。 + Object named; + Object obj = std::move(named); std::cout << "--------代码可修改区域-开始--------" << std::endl; @@ -50,10 +55,12 @@ int main() { // 关闭编译器优化 objRef.data = 1; // 修改被延长生命周期的临时对象的值(不要直接改动这行代码) std::cout << "objRef.data = " << objRef.data << " - " << &objRef << std::endl; - d2x_assert((&objRef == object_address)); + d2x::check((&objRef == object_address), "(&objRef == object_address)"); + // 钉住移动构造确实发生过。教学漂移之所以能静默发生, 正是因为 + // 从前没有任何断言检查它 —— 输出少了一行, 没人发现。 + d2x::check((move_ctor_calls >= 1), "(move_ctor_calls >= 1)"); } - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/05-move-semantics-0.cpp b/src/cpp11/tests/05-move-semantics/0.cpp similarity index 83% rename from dslings/cpp11/05-move-semantics-0.cpp rename to src/cpp11/tests/05-move-semantics/0.cpp index 2ee7f3a..a78fc14 100644 --- a/dslings/cpp11/05-move-semantics-0.cpp +++ b/src/cpp11/tests/05-move-semantics/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/05-move-semantics-0.cpp +// file: src/cpp11/tests/05-move-semantics/0.cpp // // Exercise/练习: cpp11 | 05 - move semantics | 移动构造与触发时机 // @@ -14,9 +14,9 @@ // d2x checker move-semantics // -#include +import std; +import d2x; -#include struct Buffer { int *data; @@ -57,20 +57,19 @@ int main() { Buffer buff2(std::move(buff1)); auto buff2DataPtr = buff2.data_ptr(); - d2x_assert(buff1DataPtr == buff2DataPtr); + d2x::check(buff1DataPtr == buff2DataPtr, "buff1DataPtr == buff2DataPtr"); Buffer buff3 = buff2; auto buff3DataPtr = buff3.data_ptr(); - d2x_assert(buff2DataPtr == buff3DataPtr); + d2x::check(buff2DataPtr == buff3DataPtr, "buff2DataPtr == buff3DataPtr"); Buffer buff4 = process(buff3); auto buff4DataPtr = buff4.data_ptr(); - d2x_assert(buff3DataPtr == buff4DataPtr); + d2x::check(buff3DataPtr == buff4DataPtr, "buff3DataPtr == buff4DataPtr"); } - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/05-move-semantics-1.cpp b/src/cpp11/tests/05-move-semantics/1.cpp similarity index 87% rename from dslings/cpp11/05-move-semantics-1.cpp rename to src/cpp11/tests/05-move-semantics/1.cpp index 4bbda9b..5d172cc 100644 --- a/dslings/cpp11/05-move-semantics-1.cpp +++ b/src/cpp11/tests/05-move-semantics/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/05-move-semantics-0.cpp +// file: src/cpp11/tests/05-move-semantics/1.cpp // // Exercise/练习: cpp11 | 05 - move semantics | 移动赋值与触发时机 // @@ -14,9 +14,9 @@ // d2x checker move-semantics // -#include +import std; +import d2x; -#include static int move_assignment_counter = 0; @@ -80,21 +80,20 @@ int main() { // 无编译器优化 buff1 = Buffer(); // 情况1: 临时对象赋值 - d2x_assert_eq(move_assignment_counter, 1); + d2x::check_eq(move_assignment_counter, 1, "move_assignment_counter == 1"); Buffer buff2; buff2 = process(buff1); // 情况2: 中间对象赋值 - d2x_assert_eq(move_assignment_counter, 2); + d2x::check_eq(move_assignment_counter, 2, "move_assignment_counter == 2"); buff2 = buff1; // 情况3: 显示移动赋值 - d2x_assert_eq(move_assignment_counter, 3); + d2x::check_eq(move_assignment_counter, 3, "move_assignment_counter == 3"); } - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/05-move-semantics-2.cpp b/src/cpp11/tests/05-move-semantics/2.cpp similarity index 85% rename from dslings/cpp11/05-move-semantics-2.cpp rename to src/cpp11/tests/05-move-semantics/2.cpp index 3c25e8a..30bc986 100644 --- a/dslings/cpp11/05-move-semantics-2.cpp +++ b/src/cpp11/tests/05-move-semantics/2.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/05-move-semantics-2.cpp +// file: src/cpp11/tests/05-move-semantics/2.cpp // // Exercise/练习: cpp11 | 05 - move semantics | 移动的是资源而不是对象 // @@ -14,9 +14,9 @@ // d2x checker move-semantics-2 // -#include +import std; +import d2x; -#include struct Buffer { int *data; @@ -72,13 +72,12 @@ int main() { // 移动语义 - 移动的是资源而不是对象演示 Buffer b2 = b1; // std::move(b1); - d2x_assert(&b1 != &b2); // b1 和 b2 是不同的对象 - d2x_assert(old_b1_data_ptr == b2.data_ptr()); - d2x_assert(b1.data_ptr() == nullptr); // b1 的资源被移动了 + d2x::check(&b1 != &b2, "&b1 != &b2"); // b1 和 b2 是不同的对象 + d2x::check(old_b1_data_ptr == b2.data_ptr(), "old_b1_data_ptr == b2.data_ptr()"); + d2x::check(b1.data_ptr() == nullptr, "b1.data_ptr() == nullptr"); // b1 的资源被移动了 } - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/06-scoped-enums-0.cpp b/src/cpp11/tests/06-scoped-enums/0.cpp similarity index 78% rename from dslings/cpp11/06-scoped-enums-0.cpp rename to src/cpp11/tests/06-scoped-enums/0.cpp index 1aa8b5a..f22808e 100644 --- a/dslings/cpp11/06-scoped-enums-0.cpp +++ b/src/cpp11/tests/06-scoped-enums/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/06-scoped-enums-0.cpp +// file: src/cpp11/tests/06-scoped-enums/0.cpp // // Exercise/练习: cpp11 | 06 - scoped enums | 传统枚举类型潜在问题 // @@ -14,9 +14,9 @@ // d2x checker scoped-enums // -#include +import std; +import d2x; -#include enum Color { RED, @@ -36,20 +36,19 @@ int main() { Color color = RED; Fruit fruit = Apple; - d2x_assert_eq(color, RED); - d2x_assert_eq(fruit, Apple); + d2x::check_eq(color, RED, "color == RED"); + d2x::check_eq(fruit, Apple, "fruit == Apple"); // 2.符合语法, 但逻辑错误的类型匹配 if (color == Apple) { // 不要删除这行代码 // 代码会运行到这里 - D2X_WAIT + d2x::wait(); } if (fruit == RED) { - D2X_WAIT + d2x::wait(); } - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/06-scoped-enums-1.cpp b/src/cpp11/tests/06-scoped-enums/1.cpp similarity index 69% rename from dslings/cpp11/06-scoped-enums-1.cpp rename to src/cpp11/tests/06-scoped-enums/1.cpp index 980ed3b..79b69a1 100644 --- a/dslings/cpp11/06-scoped-enums-1.cpp +++ b/src/cpp11/tests/06-scoped-enums/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/06-scoped-enums-1.cpp +// file: src/cpp11/tests/06-scoped-enums/1.cpp // // Exercise/练习: cpp11 | 06 - scoped enums | 范围枚举类型基本用法 // @@ -14,9 +14,9 @@ // d2x checker scoped-enums-1 // -#include +import std; +import d2x; -#include enum class Color { RED, @@ -37,12 +37,12 @@ int main() { Color color = Color::ORANGE; Fruit fruit = Fruit::ORANGE; - d2x_assert(color == Color::ORANGE); - d2x_assert(fruit == Fruit::ORANGE); + d2x::check(color == Color::ORANGE, "color == Color::ORANGE"); + d2x::check(fruit == Fruit::ORANGE, "fruit == Fruit::ORANGE"); // 2.类型安全: 防止不同类型的枚举值之间的比较 if (color == Fruit::ORANGE) { // 使用Color类型修复编译错误 - d2x_assert(color == Color::ORANGE); + d2x::check(color == Color::ORANGE, "color == Color::ORANGE"); } // 3.类型检查: 默认情况下, 范围枚举类型的值是不可隐式转换 @@ -56,8 +56,8 @@ int main() { ORANGE // 橙色 }; - d2x_assert_eq(sizeof(Color), sizeof(int)); // 默认类型是int - d2x_assert_eq(sizeof(Color8Bit), sizeof(int8_t)); // 可自定义类型int8_t + d2x::check_eq(sizeof(Color), sizeof(int), "sizeof(Color) == sizeof(int)"); // 默认类型是int + d2x::check_eq(sizeof(Color8Bit), sizeof(std::int8_t), "sizeof(Color8Bit) == sizeof(std::int8_t)"); // 可自定义类型int8_t // 5.自定义起始值: 默认情况下, 范围枚举类型的值从0开始, 往下递增 enum class ErrorCode : int { @@ -67,9 +67,8 @@ int main() { ERROR_3 }; - d2x_assert_eq(static_cast(ErrorCode::ERROR_3), 3); - - D2X_WAIT + d2x::check_eq(static_cast(ErrorCode::ERROR_3), 3, "static_cast(ErrorCode::ERROR_3) == 3"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/07-constexpr-0.cpp b/src/cpp11/tests/07-constexpr/0.cpp similarity index 85% rename from dslings/cpp11/07-constexpr-0.cpp rename to src/cpp11/tests/07-constexpr/0.cpp index 8c67383..d7e1222 100644 --- a/dslings/cpp11/07-constexpr-0.cpp +++ b/src/cpp11/tests/07-constexpr/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/07-constexpr-0.cpp +// file: src/cpp11/tests/07-constexpr/0.cpp // // Exercise/练习: cpp11 | 07 - constexpr | 编译期计算基础: constexpr 和 const的区别 // @@ -14,9 +14,9 @@ // d2x checker constexpr // -#include +import std; +import d2x; -#include int sum_for_1_to(int n) { return n == 1 ? 1 : n + sum_for_1_to(n - 1); @@ -34,10 +34,9 @@ int main() { { // 2. 编译期计算基础 constexpr int s = sum_for_1_to(4); - d2x_assert_eq(s, 1 + 2 + 3 + 4); + d2x::check_eq(s, 1 + 2 + 3 + 4, "s == 1 + 2 + 3 + 4"); } - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/07-constexpr-1.cpp b/src/cpp11/tests/07-constexpr/1.cpp similarity index 94% rename from dslings/cpp11/07-constexpr-1.cpp rename to src/cpp11/tests/07-constexpr/1.cpp index 1347c54..06c505a 100644 --- a/dslings/cpp11/07-constexpr-1.cpp +++ b/src/cpp11/tests/07-constexpr/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/07-constexpr-1.cpp +// file: src/cpp11/tests/07-constexpr/1.cpp // // Exercise/练习: cpp11 | 07 - constexpr | 编译期计算应用示例 // @@ -14,9 +14,9 @@ // d2x checker constexpr // -#include +import std; +import d2x; -#include template struct Sum { @@ -67,7 +67,6 @@ int main() { constexpr double sin30 = mysin(30.0); std::cout << "mysin(30): " << sin30 << " " << std::endl; - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/08-literal-type-0.cpp b/src/cpp11/tests/08-literal-type/0.cpp similarity index 91% rename from dslings/cpp11/08-literal-type-0.cpp rename to src/cpp11/tests/08-literal-type/0.cpp index 5943da4..feda694 100644 --- a/dslings/cpp11/08-literal-type-0.cpp +++ b/src/cpp11/tests/08-literal-type/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/08-literal-type-0.cpp +// file: src/cpp11/tests/08-literal-type/0.cpp // // Exercise/练习: cpp11 | 08 - literal type | 什么是字面值类型 // @@ -14,11 +14,9 @@ // d2x checker literal-type-0 // -#include +import std; +import d2x; -#include -#include -#include constexpr char compile_time_compute(char c, int a) { return a + c; @@ -54,7 +52,6 @@ int main() { std::cout << "1 + 2 + 3 = " << sum << std::endl; - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/08-literal-type-1.cpp b/src/cpp11/tests/08-literal-type/1.cpp similarity index 87% rename from dslings/cpp11/08-literal-type-1.cpp rename to src/cpp11/tests/08-literal-type/1.cpp index 59299b4..09de452 100644 --- a/dslings/cpp11/08-literal-type-1.cpp +++ b/src/cpp11/tests/08-literal-type/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/08-literal-type-1.cpp +// file: src/cpp11/tests/08-literal-type/1.cpp // // Exercise/练习: cpp11 | 08 - literal type | 自定义字面值类型 // @@ -14,9 +14,9 @@ // d2x checker literal-type-1 // -#include +import std; +import d2x; -#include struct Vector { int x, y; @@ -34,7 +34,6 @@ int main() { std::cout << "[ " << v3.x << ", " << v3.y << " ]" << std::endl; - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/09-list-initialization-0.cpp b/src/cpp11/tests/09-list-initialization/0.cpp similarity index 62% rename from dslings/cpp11/09-list-initialization-0.cpp rename to src/cpp11/tests/09-list-initialization/0.cpp index 254fc7a..f6e1a69 100644 --- a/dslings/cpp11/09-list-initialization-0.cpp +++ b/src/cpp11/tests/09-list-initialization/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/09-list-initialization-0.cpp +// file: src/cpp11/tests/09-list-initialization/0.cpp // // Exercise/练习: cpp11 | 09 - list initialization | 窄化检查 // @@ -15,19 +15,19 @@ // d2x checker list-initialization // -#include +import std; +import d2x; -#include int main() { int a1 = 1.1; - d2x_assert_eq(a1, 1); + d2x::check_eq(a1, 1, "a1 == 1"); int a2 = 1.1; int a3 = { 1.1 }; - d2x_assert_eq(a2, 1); - d2x_assert_eq(a3, 1); + d2x::check_eq(a2, 1, "a2 == 1"); + d2x::check_eq(a3, 1, "a3 == 1"); double b1 { 1.1 }; constexpr double c1 { 2.2 }; @@ -35,18 +35,17 @@ int main() { int b2 { b1 }; int c2 { c1 }; - d2x_assert_eq(b2, 1); - d2x_assert_eq(c2, 2); + d2x::check_eq(b2, 1, "b2 == 1"); + d2x::check_eq(c2, 2, "c2 == 2"); int arr1[] = { 1, 2.2, 3 }; - d2x_assert_eq(arr1[1], 2); + d2x::check_eq(arr1[1], 2, "arr1[1] == 2"); int arr2[4] { 1, b1, c1 }; - d2x_assert_eq(arr2[1], 1); - d2x_assert_eq(arr2[2], 2); - d2x_assert_eq(arr2[3], 0); - - D2X_WAIT + d2x::check_eq(arr2[1], 1, "arr2[1] == 1"); + d2x::check_eq(arr2[2], 2, "arr2[2] == 2"); + d2x::check_eq(arr2[3], 0, "arr2[3] == 0"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/09-list-initialization-1.cpp b/src/cpp11/tests/09-list-initialization/1.cpp similarity index 81% rename from dslings/cpp11/09-list-initialization-1.cpp rename to src/cpp11/tests/09-list-initialization/1.cpp index f37ac9d..a3b5e88 100644 --- a/dslings/cpp11/09-list-initialization-1.cpp +++ b/src/cpp11/tests/09-list-initialization/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/09-list-initialization-1.cpp +// file: src/cpp11/tests/09-list-initialization/1.cpp // // Exercise/练习: cpp11 | 09 - list initialization | 默认初始化语法陷阱 // @@ -15,9 +15,9 @@ // d2x checker list-initialization // -#include +import std; +import d2x; -#include struct Object { Object() { @@ -35,10 +35,9 @@ int main() { Object obj1(); Object obj2(2); - d2x_assert_eq(obj1.x, 0); - d2x_assert_eq(obj2.x, 2); - - D2X_WAIT + d2x::check_eq(obj1.x, 0, "obj1.x == 0"); + d2x::check_eq(obj2.x, 2, "obj2.x == 2"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/09-list-initialization-2.cpp b/src/cpp11/tests/09-list-initialization/2.cpp similarity index 74% rename from dslings/cpp11/09-list-initialization-2.cpp rename to src/cpp11/tests/09-list-initialization/2.cpp index d1aee65..eefc9b2 100644 --- a/dslings/cpp11/09-list-initialization-2.cpp +++ b/src/cpp11/tests/09-list-initialization/2.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/09-list-initialization-2.cpp +// file: src/cpp11/tests/09-list-initialization/2.cpp // // Exercise/练习: cpp11 | 09 - list initialization | 容器列表初始化 // @@ -16,11 +16,9 @@ // d2x checker list-initialization // -#include +import std; +import d2x; -#include -#include -#include class MyVector { int mSize; @@ -36,16 +34,15 @@ class MyVector { int main() { std::vector vec1 = { 1, 2, 3 }; - d2x_assert_eq(vec1.size(), 3); + d2x::check_eq(vec1.size(), 3, "vec1.size() == 3"); std::vector vec2 { 1, 2, 3, 4, 5 }; - d2x_assert_eq(vec2.size(), 5); + d2x::check_eq(vec2.size(), 5, "vec2.size() == 5"); MyVector myVec1 = { 1, 2, 3 }; - d2x_assert_eq(myVec1.size(), 3); + d2x::check_eq(myVec1.size(), 3, "myVec1.size() == 3"); MyVector myVec2 { 1, 2, 3, 4, 5 }; - d2x_assert_eq(myVec2.size(), 5); - - D2X_WAIT + d2x::check_eq(myVec2.size(), 5, "myVec2.size() == 5"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/09-list-initialization-3.cpp b/src/cpp11/tests/09-list-initialization/3.cpp similarity index 82% rename from dslings/cpp11/09-list-initialization-3.cpp rename to src/cpp11/tests/09-list-initialization/3.cpp index 0f80762..ea2e2da 100644 --- a/dslings/cpp11/09-list-initialization-3.cpp +++ b/src/cpp11/tests/09-list-initialization/3.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/09-list-initialization-3.cpp +// file: src/cpp11/tests/09-list-initialization/3.cpp // // Exercise/练习: cpp11 | 09 - list initialization | 注意事项 // @@ -16,11 +16,9 @@ // d2x checker list-initialization // -#include +import std; +import d2x; -#include -#include -#include class MyVector { int mSize; @@ -73,16 +71,15 @@ int main() { Point p2 {3, 4}; MyVector vec1(1); - d2x_assert_eq(vec1.size(), 1); + d2x::check_eq(vec1.size(), 1, "vec1.size() == 1"); MyVector vec2 { 1 }; - d2x_assert_eq(vec2.size(), 1); + d2x::check_eq(vec2.size(), 1, "vec2.size() == 1"); MyVector vec3(1, 10); - d2x_assert_eq(vec3.size(), 10); + d2x::check_eq(vec3.size(), 10, "vec3.size() == 10"); MyVector vec4 { 1, 10 }; - d2x_assert_eq(vec4.size(), 10); - - D2X_WAIT + d2x::check_eq(vec4.size(), 10, "vec4.size() == 10"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/10-delegating-constructors-0.cpp b/src/cpp11/tests/10-delegating-constructors/0.cpp similarity index 70% rename from dslings/cpp11/10-delegating-constructors-0.cpp rename to src/cpp11/tests/10-delegating-constructors/0.cpp index 2ed5578..9471ee0 100644 --- a/dslings/cpp11/10-delegating-constructors-0.cpp +++ b/src/cpp11/tests/10-delegating-constructors/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/10-delegating-constructors-0.cpp +// file: src/cpp11/tests/10-delegating-constructors/0.cpp // // Exercise/练习: cpp11 | 10 - delegating constructors | 委托构造函数 // @@ -15,10 +15,9 @@ // d2x checker delegating-constructors // -#include +import std; +import d2x; -#include -#include static int construction_counter { 0 }; @@ -33,7 +32,7 @@ class Account { name = "momo"; coin = "0元"; - D2X_DONT_DELETE_THIS(construction_counter++); + d2x::dont_delete_this(construction_counter++); } Account(std::string id_, std::string name_) { @@ -41,7 +40,7 @@ class Account { name = name_; coin = "0元"; - D2X_DONT_DELETE_THIS(construction_counter++); + d2x::dont_delete_this(construction_counter++); } Account(std::string id_, std::string name_, int coin_) { @@ -49,7 +48,7 @@ class Account { name = name_; coin = std::to_string(coin_) + "元"; - D2X_DONT_DELETE_THIS(construction_counter++); + d2x::dont_delete_this(construction_counter++); } std::string to_string() const { @@ -60,26 +59,23 @@ class Account { int main() { // 不要修改main函数中的代码 Account a1 { "1111" }; - d2x_assert_eq(construction_counter, 3); + d2x::check_eq(construction_counter, 3, "construction_counter == 3"); std::cout << a1.to_string() << std::endl; Account a2 { "2222", "wukong" }; - d2x_assert_eq(construction_counter, 5); + d2x::check_eq(construction_counter, 5, "construction_counter == 5"); std::cout << a2.to_string() << std::endl; Account a3 { "3333", "mcpp", 100 }; - d2x_assert_eq(construction_counter, 6); + d2x::check_eq(construction_counter, 6, "construction_counter == 6"); std::cout << a3.to_string() << std::endl; Account gi { "0000", "GImpact", 648 }; std::cout << gi.to_string() << std::endl; - d2x_assert( - gi.to_string() == - "Account { id: 0000, name: GImpact, coin: 648原石 }" - ); - - D2X_WAIT + d2x::check(gi.to_string() == + "Account { id: 0000, name: GImpact, coin: 648原石 }", "gi.to_string() == \"Account { id: 0000, name: GImpact, coin: 648原石 }\""); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/10-delegating-constructors-1.cpp b/src/cpp11/tests/10-delegating-constructors/1.cpp similarity index 85% rename from dslings/cpp11/10-delegating-constructors-1.cpp rename to src/cpp11/tests/10-delegating-constructors/1.cpp index 6dbbd57..db72db0 100644 --- a/dslings/cpp11/10-delegating-constructors-1.cpp +++ b/src/cpp11/tests/10-delegating-constructors/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/10-delegating-constructors-1.cpp +// file: src/cpp11/tests/10-delegating-constructors/1.cpp // // Exercise/练习: cpp11 | 10 - delegating constructors | 委托构造函数注意事项 // @@ -15,10 +15,9 @@ // d2x checker delegating-constructors // -#include +import std; +import d2x; -#include -#include struct Object { // 不要修改这个类的代码 static int construction_counter; @@ -77,16 +76,15 @@ int main() { // 不要修改main函数中的代码 Account a1 { "1111", "hello" }; std::cout << a1.to_string() << std::endl; - d2x_assert(a1.get_id() == "1111"); + d2x::check(a1.get_id() == "1111", "a1.get_id() == \"1111\""); Object::construction_counter = 0; Account a2 { "2222", "d2learn", 100 }; std::cout << a2.to_string() << std::endl; - d2x_assert(a2.get_object_name() == "d2learn"); - d2x_assert_eq(Object::construction_counter, 1); - - D2X_WAIT + d2x::check(a2.get_object_name() == "d2learn", "a2.get_object_name() == \"d2learn\""); + d2x::check_eq(Object::construction_counter, 1, "Object::construction_counter == 1"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/11-inherited-constructors-0.cpp b/src/cpp11/tests/11-inherited-constructors/0.cpp similarity index 92% rename from dslings/cpp11/11-inherited-constructors-0.cpp rename to src/cpp11/tests/11-inherited-constructors/0.cpp index 8ac418a..5457644 100644 --- a/dslings/cpp11/11-inherited-constructors-0.cpp +++ b/src/cpp11/tests/11-inherited-constructors/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/11-inherited-constructors-0.cpp +// file: src/cpp11/tests/11-inherited-constructors/0.cpp // // Exercise/练习: cpp11 | 11 - inherited constructors | 继承构造函数 // @@ -15,10 +15,9 @@ // d2x checker inherited-constructors // -#include +import std; +import d2x; -#include -#include class ObjectBase { public: @@ -66,7 +65,6 @@ int main() { // 不要直接修改 main 函数中的代码 a1.tips_a(); b1.tips_b(); - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/11-inherited-constructors-1.cpp b/src/cpp11/tests/11-inherited-constructors/1.cpp similarity index 62% rename from dslings/cpp11/11-inherited-constructors-1.cpp rename to src/cpp11/tests/11-inherited-constructors/1.cpp index 3e49842..352194f 100644 --- a/dslings/cpp11/11-inherited-constructors-1.cpp +++ b/src/cpp11/tests/11-inherited-constructors/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/11-inherited-constructors-1.cpp +// file: src/cpp11/tests/11-inherited-constructors/1.cpp // // Exercise/练习: cpp11 | 11 - inherited constructors | 继承构造函数于功能扩展 // @@ -15,10 +15,9 @@ // d2x checker inherited-constructors // -#include +import std; +import d2x; -#include -#include class Student { // 不要直接修改 Student 类中的代码 protected: @@ -62,35 +61,34 @@ int main() { // 不要直接修改 main 函数中的代码 { // 基础测试 StudentTest studentTest; - d2x_assert(studentTest.age_valid() == true); - d2x_assert(studentTest.score_valid() == true); - d2x_assert(studentTest.to_string() == "{001, 张三, 18, 0}"); + d2x::check(studentTest.age_valid() == true, "studentTest.age_valid() == true"); + d2x::check(studentTest.score_valid() == true, "studentTest.score_valid() == true"); + d2x::check(studentTest.to_string() == "{001, 张三, 18, 0}", "studentTest.to_string() == \"{001, 张三, 18, 0}\""); } { // 边界测试 StudentTest studentTest("002", "张三", 201); - d2x_assert(studentTest.score_valid() == true); - d2x_assert(studentTest.age_valid() == false); + d2x::check(studentTest.score_valid() == true, "studentTest.score_valid() == true"); + d2x::check(studentTest.age_valid() == false, "studentTest.age_valid() == false"); studentTest.set_score(101); studentTest.set_age(200); - d2x_assert(studentTest.score_valid() == false); - d2x_assert(studentTest.age_valid() == true); + d2x::check(studentTest.score_valid() == false, "studentTest.score_valid() == false"); + d2x::check(studentTest.age_valid() == true, "studentTest.age_valid() == true"); studentTest.set_score(0); studentTest.set_age(1); - d2x_assert(studentTest.score_valid() == true); - d2x_assert(studentTest.age_valid() == true); + d2x::check(studentTest.score_valid() == true, "studentTest.score_valid() == true"); + d2x::check(studentTest.age_valid() == true, "studentTest.age_valid() == true"); studentTest.set_score(-1); studentTest.set_age(0); - d2x_assert(studentTest.score_valid() == false); - d2x_assert(studentTest.age_valid() == false); + d2x::check(studentTest.score_valid() == false, "studentTest.score_valid() == false"); + d2x::check(studentTest.age_valid() == false, "studentTest.age_valid() == false"); } - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/11-inherited-constructors-2.cpp b/src/cpp11/tests/11-inherited-constructors/2.cpp similarity index 80% rename from dslings/cpp11/11-inherited-constructors-2.cpp rename to src/cpp11/tests/11-inherited-constructors/2.cpp index 02d5171..b354821 100644 --- a/dslings/cpp11/11-inherited-constructors-2.cpp +++ b/src/cpp11/tests/11-inherited-constructors/2.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/11-inherited-constructors-2.cpp +// file: src/cpp11/tests/11-inherited-constructors/2.cpp // // Exercise/练习: cpp11 | 11 - inherited constructors | 继承构造函数在泛型装饰器的应用 // @@ -16,10 +16,9 @@ // d2x checker inherited-constructors // -#include +import std; +import d2x; -#include -#include struct Point { double mX, mY; @@ -54,13 +53,13 @@ int main() { auto p11 = p1; std::cout << "p11: " << p11.to_string() << std::endl; - d2x_assert_eq(p1.mX, p11.mX); - d2x_assert_eq(p1.mY, p11.mY); + d2x::check_eq(p1.mX, p11.mX, "p1.mX == p11.mX"); + d2x::check_eq(p1.mY, p11.mY, "p1.mY == p11.mY"); decltype(p2) p22 = p2; // by std::move? std::cout << "p22: " << p22.to_string() << std::endl; - d2x_assert_eq(p2.mX, p22.mX); - d2x_assert_eq(p2.mY, p22.mY); + d2x::check_eq(p2.mX, p22.mX, "p2.mX == p22.mX"); + d2x::check_eq(p2.mY, p22.mY, "p2.mY == p22.mY"); NoMove p3(3, 3); std::cout << "p3: " << p3.to_string() << std::endl; @@ -68,10 +67,9 @@ int main() { NoMove p33(0, 0); p33 = std::move(p3); // by copy? std::cout << "p33: " << p33.to_string() << std::endl; - d2x_assert_eq(p3.mX, p33.mX); - d2x_assert_eq(p3.mY, p33.mY); - - D2X_WAIT + d2x::check_eq(p3.mX, p33.mX, "p3.mX == p33.mX"); + d2x::check_eq(p3.mY, p33.mY, "p3.mY == p33.mY"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/cpp11/12-nullptr-0.cpp b/src/cpp11/tests/12-nullptr/0.cpp similarity index 67% rename from dslings/cpp11/12-nullptr-0.cpp rename to src/cpp11/tests/12-nullptr/0.cpp index 44da275..72f72f8 100644 --- a/dslings/cpp11/12-nullptr-0.cpp +++ b/src/cpp11/tests/12-nullptr/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/12-nullptr-0.cpp +// file: src/cpp11/tests/12-nullptr/0.cpp // // Exercise/练习: cpp11 | 12 - nullptr | 指针字面量 - 基础用法 // @@ -17,9 +17,10 @@ // d2x checker nullptr // -#include +#include // NULL 宏是这一课的教具,import std 不带宏 +import std; +import d2x; -#include int main() { @@ -28,13 +29,13 @@ int main() { int* ptr2 = NULL; // 修复这里,添加正确类型 int* ptr3 = 0; // 不推荐的传统用法 - d2x_assert(ptr1 == nullptr); - d2x_assert(ptr2 == nullptr); - d2x_assert(ptr3 == nullptr); + d2x::check(ptr1 == nullptr, "ptr1 == nullptr"); + d2x::check(ptr2 == nullptr, "ptr2 == nullptr"); + d2x::check(ptr3 == nullptr, "ptr3 == nullptr"); // 2. nullptr的类型 bool ok = std::is_same::value; - d2x_assert(ok); + d2x::check(ok, "ok"); // 3. 使用 nullptr 进行指针比较 int value = 42; @@ -42,7 +43,7 @@ int main() { if (ptr4 != nullptr) { *ptr4 = D2X_YOUR_ANSWER; - d2x_assert_eq(*ptr4, 2233); + d2x::check_eq(*ptr4, 2233, "*ptr4 == 2233"); } // 4. 不同类型的指针都可以使用 nullptr @@ -50,11 +51,10 @@ int main() { char* cptr = nullptr void* vptr = nullptr; - d2x_assert(dptr == nullptr); - d2x_assert(cptr == nullptr); - d2x_assert(vptr == nullptr); - - D2X_WAIT + d2x::check(dptr == nullptr, "dptr == nullptr"); + d2x::check(cptr == nullptr, "cptr == nullptr"); + d2x::check(vptr == nullptr, "vptr == nullptr"); + d2x::wait(); return 0; } diff --git a/dslings/cpp11/12-nullptr-1.cpp b/src/cpp11/tests/12-nullptr/1.cpp similarity index 75% rename from dslings/cpp11/12-nullptr-1.cpp rename to src/cpp11/tests/12-nullptr/1.cpp index 671e32c..1fd6549 100644 --- a/dslings/cpp11/12-nullptr-1.cpp +++ b/src/cpp11/tests/12-nullptr/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/12-nullptr-1.cpp +// file: src/cpp11/tests/12-nullptr/1.cpp // // Exercise/练习: cpp11 | 12 - nullptr | 指针字面量 - 函数重载 // @@ -17,7 +17,8 @@ // d2x checker nullptr // -#include +import std; +import d2x; bool process_int_called = false; bool process_ptr_called = false; @@ -47,12 +48,11 @@ int main() { display(NULL); process(NULL); - d2x_assert(process_int_called); - d2x_assert(display_int_called); - d2x_assert(display_ptr_called); - d2x_assert(display_ptr_called); - - D2X_WAIT + d2x::check(process_int_called, "process_int_called"); + d2x::check(display_int_called, "display_int_called"); + d2x::check(display_ptr_called, "display_ptr_called"); + d2x::check(display_ptr_called, "display_ptr_called"); + d2x::wait(); return 0; } diff --git a/dslings/cpp11/12-nullptr-2.cpp b/src/cpp11/tests/12-nullptr/2.cpp similarity index 88% rename from dslings/cpp11/12-nullptr-2.cpp rename to src/cpp11/tests/12-nullptr/2.cpp index cb1f5fe..81d7a8d 100644 --- a/dslings/cpp11/12-nullptr-2.cpp +++ b/src/cpp11/tests/12-nullptr/2.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/12-nullptr-2.cpp +// file: src/cpp11/tests/12-nullptr/2.cpp // // Exercise/练习: cpp11 | 12 - nullptr | 指针字面量 - 模板编程 // @@ -17,8 +17,9 @@ // d2x checker nullptr // -#include -#include +#include // NULL 宏是这一课的教具,import std 不带宏 +import std; +import d2x; // 模板函数示例 template @@ -44,7 +45,6 @@ int main() { processPointer(clone(nullptr)); processPointer(clone(nullptr)); - D2X_WAIT - + d2x::wait(); return 0; } diff --git a/dslings/cpp11/13-long-long-0.cpp b/src/cpp11/tests/13-long-long/0.cpp similarity index 78% rename from dslings/cpp11/13-long-long-0.cpp rename to src/cpp11/tests/13-long-long/0.cpp index b25e40c..f858057 100644 --- a/dslings/cpp11/13-long-long-0.cpp +++ b/src/cpp11/tests/13-long-long/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/13-long-long-0.cpp +// file: src/cpp11/tests/13-long-long/0.cpp // // Exercise/练习: cpp11 | 13 - long long | 64位整数类型 - 基础用法 // @@ -17,9 +17,9 @@ // d2x checker long-long // -#include +import std; +import d2x; -#include int main() { @@ -29,7 +29,7 @@ int main() { // 2. 整数表示范围 unsigned int uVal1 = 18446744073709551615; - d2x_assert_eq(uVal1, 18446744073709551615ULL); + d2x::check_eq(uVal1, 18446744073709551615ULL, "uVal1 == 18446744073709551615ULL"); // 3. 类型推导和字面量 // 修复下面的声明,让 auto 正确推导类型 @@ -39,10 +39,9 @@ int main() { bool is_longlong = std::is_same::value; bool is_ulonglong = std::is_same::value; - d2x_assert(is_longlong == true); - d2x_assert(is_ulonglong == true); - - D2X_WAIT + d2x::check(is_longlong == true, "is_longlong == true"); + d2x::check(is_ulonglong == true, "is_ulonglong == true"); + d2x::wait(); return 0; } diff --git a/dslings/cpp11/13-long-long-1.cpp b/src/cpp11/tests/13-long-long/1.cpp similarity index 64% rename from dslings/cpp11/13-long-long-1.cpp rename to src/cpp11/tests/13-long-long/1.cpp index 26a5461..119747f 100644 --- a/dslings/cpp11/13-long-long-1.cpp +++ b/src/cpp11/tests/13-long-long/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/13-long-long-1.cpp +// file: src/cpp11/tests/13-long-long/1.cpp // // Exercise/练习: cpp11 | 13 - long long | 64位整数类型 - 大数应用和边界值 // @@ -17,9 +17,9 @@ // d2x checker long-long // -#include +import std; +import d2x; -#include int main() { @@ -29,16 +29,15 @@ int main() { auto minLL = std::numeric_limits::min(); auto maxULL = std::numeric_limits::max(); - d2x_assert_eq(maxInt, 2147483647); - d2x_assert_eq(maxLL, 9223372036854775807LL); - d2x_assert_eq(minLL, -9223372036854775807LL - 1); - d2x_assert_eq(maxULL, 18446744073709551615ULL); + d2x::check_eq(maxInt, 2147483647, "maxInt == 2147483647"); + d2x::check_eq(maxLL, 9223372036854775807LL, "maxLL == 9223372036854775807LL"); + d2x::check_eq(minLL, -9223372036854775807LL - 1, "minLL == -9223372036854775807LL - 1"); + d2x::check_eq(maxULL, 18446744073709551615ULL, "maxULL == 18446744073709551615ULL"); // 2. 大整数应用 - 表示世界人口 int currentPopulation = 7800000000; - d2x_assert_eq(currentPopulation, 7800000000ULL); - - D2X_WAIT + d2x::check_eq(currentPopulation, 7800000000ULL, "currentPopulation == 7800000000ULL"); + d2x::wait(); return 0; } diff --git a/dslings/cpp11/14-type-alias-0.cpp b/src/cpp11/tests/14-type-alias/0.cpp similarity index 72% rename from dslings/cpp11/14-type-alias-0.cpp rename to src/cpp11/tests/14-type-alias/0.cpp index d7b255f..f55b741 100644 --- a/dslings/cpp11/14-type-alias-0.cpp +++ b/src/cpp11/tests/14-type-alias/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/14-type-alias-0.cpp +// file: src/cpp11/tests/14-type-alias/0.cpp // // Exercise/练习: cpp11 | 14 - type alias | 基本类型别名 // @@ -17,9 +17,9 @@ // d2x checker type-alias // -#include +import std; +import d2x; -#include int main() { @@ -27,24 +27,23 @@ int main() { D2X_YOUR_ANSWER Integer = int; D2X_YOUR_ANSWER = int; - bool ok = std::is_same::value; d2x_assert(ok); - ok = std::is_same::value; d2x_assert(ok); + bool ok = std::is_same::value; d2x::check(ok, "ok"); + ok = std::is_same::value; d2x::check(ok, "ok"); // 2. 使用类型别名 Integer a = 42; Real b = 3.14; // 3. 验证类型别名 - d2x_assert_eq(a, 42); - d2x_assert_eq(b, 3.14); + d2x::check_eq(a, 42, "a == 42"); + d2x::check_eq(b, 3.14, "b == 3.14"); // 4. 类型别名本质相同 int c = 100; Integer d = c; // 可以赋值,因为本质都是int - d2x_assert_eq(c, d); - - D2X_WAIT + d2x::check_eq(c, d, "c == d"); + d2x::wait(); return 0; } diff --git a/dslings/cpp11/14-type-alias-1.cpp b/src/cpp11/tests/14-type-alias/1.cpp similarity index 78% rename from dslings/cpp11/14-type-alias-1.cpp rename to src/cpp11/tests/14-type-alias/1.cpp index 1edf7da..8f9baad 100644 --- a/dslings/cpp11/14-type-alias-1.cpp +++ b/src/cpp11/tests/14-type-alias/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/14-type-alias-1.cpp +// file: src/cpp11/tests/14-type-alias/1.cpp // // Exercise/练习: cpp11 | 14 - type alias | 复杂类型和函数指针别名 // @@ -17,10 +17,9 @@ // d2x checker type-alias // -#include +import std; +import d2x; -#include -#include static int func_called = 0; @@ -37,7 +36,7 @@ int main() { FuncPtr func = example_func; func(1, 2); - d2x_assert_eq(func_called, 3); + d2x::check_eq(func_called, 3, "func_called == 3"); // 2. 容器类型别名 // 使用using定义vector的别名 @@ -54,11 +53,10 @@ int main() { Container::ValueType value = 100; // 4. 验证类型别名 - d2x_assert(strings[0] == "hello"); - d2x_assert(strings[1] == "world"); - d2x_assert_eq(value, 100); - - D2X_WAIT + d2x::check(strings[0] == "hello", "strings[0] == \"hello\""); + d2x::check(strings[1] == "world", "strings[1] == \"world\""); + d2x::check_eq(value, 100, "value == 100"); + d2x::wait(); return 0; } diff --git a/dslings/cpp11/14-type-alias-2.cpp b/src/cpp11/tests/14-type-alias/2.cpp similarity index 70% rename from dslings/cpp11/14-type-alias-2.cpp rename to src/cpp11/tests/14-type-alias/2.cpp index 53c12a3..e4603a0 100644 --- a/dslings/cpp11/14-type-alias-2.cpp +++ b/src/cpp11/tests/14-type-alias/2.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/14-type-alias-2.cpp +// file: src/cpp11/tests/14-type-alias/2.cpp // // Exercise/练习: cpp11 | 14 - type alias | 别名模板基础 // @@ -17,11 +17,9 @@ // d2x checker type-alias // -#include +import std; +import d2x; -#include -#include -#include // 1. 基本别名模板 template @@ -41,15 +39,14 @@ int main() { Vec3 v3 = {1.0f, 2.0f, 3.0f}; Heap minHeap; - d2x_assert_eq(numbers[0], 1); - d2x_assert_eq(numbers[1], 2); - d2x_assert_eq(numbers[2], 3); + d2x::check_eq(numbers[0], 1, "numbers[0] == 1"); + d2x::check_eq(numbers[1], 2, "numbers[1] == 2"); + d2x::check_eq(numbers[2], 3, "numbers[2] == 3"); - d2x_assert_eq(v3[0], 1.0f); - d2x_assert_eq(v3[1], 2.0f); - d2x_assert_eq(v3[2], 3.0f); - - D2X_WAIT + d2x::check_eq(v3[0], 1.0f, "v3[0] == 1.0f"); + d2x::check_eq(v3[1], 2.0f, "v3[1] == 2.0f"); + d2x::check_eq(v3[2], 3.0f, "v3[2] == 3.0f"); + d2x::wait(); return 0; } diff --git a/dslings/cpp11/14-type-alias-3.cpp b/src/cpp11/tests/14-type-alias/3.cpp similarity index 83% rename from dslings/cpp11/14-type-alias-3.cpp rename to src/cpp11/tests/14-type-alias/3.cpp index 815f6ee..e7a5ec9 100644 --- a/dslings/cpp11/14-type-alias-3.cpp +++ b/src/cpp11/tests/14-type-alias/3.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/14-type-alias-3.cpp +// file: src/cpp11/tests/14-type-alias/3.cpp // // Exercise/练习: cpp11 | 14 - type alias | 标准库中的别名模板应用 // @@ -17,8 +17,8 @@ // d2x checker type-alias // -#include -#include +import std; +import d2x; int main() { @@ -30,10 +30,9 @@ int main() { bool ok = std::is_same, int*>::value; - d2x_assert(ok); - d2x_assert_eq(*ptr, 20); - - D2X_WAIT + d2x::check(ok, "ok"); + d2x::check_eq(*ptr, 20, "*ptr == 20"); + d2x::wait(); return 0; } diff --git a/dslings/cpp11/15-variadic-templates-0.cpp b/src/cpp11/tests/15-variadic-templates/0.cpp similarity index 86% rename from dslings/cpp11/15-variadic-templates-0.cpp rename to src/cpp11/tests/15-variadic-templates/0.cpp index e2774ad..278b934 100644 --- a/dslings/cpp11/15-variadic-templates-0.cpp +++ b/src/cpp11/tests/15-variadic-templates/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/15-variadic-templates-0.cpp +// file: src/cpp11/tests/15-variadic-templates/0.cpp // // Exercise/练习: cpp11 | 15 - variadic templates | 可变参数模板基础 // @@ -20,8 +20,8 @@ // d2x checker variadic-templates // -#include -#include +import std; +import d2x; std::stringstream ss; @@ -41,9 +41,8 @@ int main() { print(1, "hello", 3.14); std::string result = ss.str(); - d2x_assert(result == "1 hello 3.14 "); - - D2X_WAIT + d2x::check(result == "1 hello 3.14 ", "result == \"1 hello 3.14 \""); + d2x::wait(); return 0; } diff --git a/dslings/cpp11/15-variadic-templates-1.cpp b/src/cpp11/tests/15-variadic-templates/1.cpp similarity index 78% rename from dslings/cpp11/15-variadic-templates-1.cpp rename to src/cpp11/tests/15-variadic-templates/1.cpp index c7453ab..6eaefb8 100644 --- a/dslings/cpp11/15-variadic-templates-1.cpp +++ b/src/cpp11/tests/15-variadic-templates/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/15-variadic-templates-1.cpp +// file: src/cpp11/tests/15-variadic-templates/1.cpp // // Exercise/练习: cpp11 | 15 - variadic templates | 可变参数模板求和 // @@ -13,7 +13,8 @@ // - https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/15-variadic-templates.md // -#include +import std; +import d2x; D2X_YOUR_ANSWER @@ -24,17 +25,16 @@ T sum(T first, D2X_YOUR_ANSWER) { int main() { int res1 = sum(1, 2, 3, 4, 5); - d2x_assert_eq(res1, 15); + d2x::check_eq(res1, 15, "res1 == 15"); double res2 = sum(1.5, 2.5, 3.0); - d2x_assert(res2 == 7.0); + d2x::check(res2 == 7.0, "res2 == 7.0"); // 混合类型 // 注意: 返回类型由第一个参数 T 决定 int res3 = sum(10, 20.5); - d2x_assert_eq(res3, 30); - - D2X_WAIT + d2x::check_eq(res3, 30, "res3 == 30"); + d2x::wait(); return 0; } diff --git a/dslings/cpp11/16-generalized-unions-0.cpp b/src/cpp11/tests/16-generalized-unions/0.cpp similarity index 85% rename from dslings/cpp11/16-generalized-unions-0.cpp rename to src/cpp11/tests/16-generalized-unions/0.cpp index 0511f62..ce5c71f 100644 --- a/dslings/cpp11/16-generalized-unions-0.cpp +++ b/src/cpp11/tests/16-generalized-unions/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/16-generalized-unions-0.cpp +// file: src/cpp11/tests/16-generalized-unions/0.cpp // // Exercise/练习: cpp11 | 16 - generalized unions | 广义非平凡联合体 // @@ -18,7 +18,8 @@ // d2x checker generalized-unions // -#include +import std; +import d2x; union M @@ -34,7 +35,7 @@ int main() { M u1; //初始化成员 - d2x_assert(u1.a1 == 42); + d2x::check(u1.a1 == 42, "u1.a1 == 42"); u1.a2 = 21; double val = 3.14; @@ -42,7 +43,6 @@ int main() { u1.c = 'x'; - D2X_WAIT - + d2x::wait(); return 0; } diff --git a/dslings/cpp11/16-generalized-unions-1.cpp b/src/cpp11/tests/16-generalized-unions/1.cpp similarity index 86% rename from dslings/cpp11/16-generalized-unions-1.cpp rename to src/cpp11/tests/16-generalized-unions/1.cpp index b658310..df7d1b7 100644 --- a/dslings/cpp11/16-generalized-unions-1.cpp +++ b/src/cpp11/tests/16-generalized-unions/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/16-generalized-unions-1.cpp +// file: src/cpp11/tests/16-generalized-unions/1.cpp // // Exercise/练习: cpp11 | 16 - generalized unions | 广义非平凡联合体 // @@ -18,8 +18,8 @@ // d2x checker generalized-unions // -#include -#include +import std; +import d2x; union M { @@ -43,12 +43,11 @@ int main() { u1.a2 = {1, D2X_YOUR_ANSWER, 3}; // 2. 验证:正常访问 - d2x_assert_eq(u1.a2[1], 42); + d2x::check_eq(u1.a2[1], 42, "u1.a2[1] == 42"); // 3. 手动析构 u1.a2.~vector(); - D2X_WAIT - + d2x::wait(); return 0; } diff --git a/dslings/cpp11/16-generalized-unions-2.cpp b/src/cpp11/tests/16-generalized-unions/2.cpp similarity index 80% rename from dslings/cpp11/16-generalized-unions-2.cpp rename to src/cpp11/tests/16-generalized-unions/2.cpp index 57bd336..21ab994 100644 --- a/dslings/cpp11/16-generalized-unions-2.cpp +++ b/src/cpp11/tests/16-generalized-unions/2.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/16-generalized-unions-2.cpp +// file: src/cpp11/tests/16-generalized-unions/2.cpp // // Exercise/练习: cpp11 | 16 - generalized unions | 带标签的鉴别联合体 // @@ -20,9 +20,8 @@ // d2x checker generalized-unions // -#include -#include -#include +import std; +import d2x; // 标签类型 — 标记联合体中哪个成员是活跃的 enum class Tag { @@ -77,29 +76,28 @@ int main() { // 1. 构造 int 值并验证 Value v1(42); - d2x_assert(v1.tag == Tag::INTEGER); - d2x_assert_eq(v1.as_int(), 42); + d2x::check(v1.tag == Tag::INTEGER, "v1.tag == Tag::INTEGER"); + d2x::check_eq(v1.as_int(), 42, "v1.as_int() == 42"); // 2. 构造 string 值并验证 Value v2(std::string("hello")); - d2x_assert(v2.tag == Tag::STRING); - d2x_assert(v2.as_string() == "hello"); + d2x::check(v2.tag == Tag::STRING, "v2.tag == Tag::STRING"); + d2x::check(v2.as_string() == "hello", "v2.as_string() == \"hello\""); // 3. 从 string 切换到 int { Value v3(std::string("world")); - d2x_assert(v3.as_string() == "world"); + d2x::check(v3.as_string() == "world", "v3.as_string() == \"world\""); // 手动析构 string 成员, 切换到 int v3.data.s.~basic_string(); v3.tag = Tag::INTEGER; v3.data.i = 100; - d2x_assert_eq(v3.as_int(), D2X_YOUR_ANSWER); + d2x::check_eq(v3.as_int(), D2X_YOUR_ANSWER, "v3.as_int() == D2X_YOUR_ANSWER"); // 离开作用域时 ~Value() 发现 tag == INTEGER, 不析构 string } - D2X_WAIT - + d2x::wait(); return 0; } diff --git a/dslings/cpp11/17-pod-type-0.cpp b/src/cpp11/tests/17-pod-type/0.cpp similarity index 88% rename from dslings/cpp11/17-pod-type-0.cpp rename to src/cpp11/tests/17-pod-type/0.cpp index 718ded2..407b6db 100644 --- a/dslings/cpp11/17-pod-type-0.cpp +++ b/src/cpp11/tests/17-pod-type/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/17-pod-type-0.cpp +// file: src/cpp11/tests/17-pod-type/0.cpp // // Exercise/练习: cpp11 | 17 - POD Type | 基本类型性质判断 // @@ -18,9 +18,9 @@ // // d2x checker pod-type -#include +import std; +import d2x; -#include struct A { int x; @@ -53,19 +53,19 @@ int main() { // 3. 判断 A 是否是 trivial /standard_layout 类型,将结果写入 ok bool ok = D2X_YOUR_ANSWER; - d2x_assert(ok); + d2x::check(ok, "ok"); // 4. 判断 B 是否是 trivial /standard_layout 类型,将结果写入 ok ok = D2X_YOUR_ANSWER; - d2x_assert(ok); + d2x::check(ok, "ok"); // 5. 判断 C 是否是 trivial 类型,将结果写入 ok ok = D2X_YOUR_ANSWER; - d2x_assert(ok); + d2x::check(ok, "ok"); // 6. 判断 D 是否不是 standard_layout 类型,将结果写入 ok ok = D2X_YOUR_ANSWER; - d2x_assert(!ok); + d2x::check(!ok, "!ok"); - D2X_WAIT + d2x::wait(); } diff --git a/dslings/cpp11/17-pod-type-1.cpp b/src/cpp11/tests/17-pod-type/1.cpp similarity index 73% rename from dslings/cpp11/17-pod-type-1.cpp rename to src/cpp11/tests/17-pod-type/1.cpp index 37d417f..fcfa251 100644 --- a/dslings/cpp11/17-pod-type-1.cpp +++ b/src/cpp11/tests/17-pod-type/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/17-pod-type-1.cpp +// file: src/cpp11/tests/17-pod-type/1.cpp // // Exercise/练习: cpp11 | 17 - POD Type | 按字节拷贝 POD 结构体 // @@ -18,10 +18,9 @@ // // d2x checker pod-type -#include +import std; +import d2x; -#include -#include struct Packet { @@ -41,12 +40,11 @@ int main() { // TODO: 使用内存拷贝将 p1 的内容复制到 p2 D2X_YOUR_ANSWER; - d2x_assert_eq(p2.len, 42u); - d2x_assert_eq(p2.type, static_cast(1)); - d2x_assert_eq(p2.flags, static_cast(0xFF)); - - D2X_WAIT + d2x::check_eq(p2.len, 42u, "p2.len == 42u"); + d2x::check_eq(p2.type, static_cast(1), "p2.type == static_cast(1)"); + d2x::check_eq(p2.flags, static_cast(0xFF), "p2.flags == static_cast(0xFF)"); + d2x::wait(); return 0; } diff --git a/dslings/cpp11/17-pod-type-2.cpp b/src/cpp11/tests/17-pod-type/2.cpp similarity index 78% rename from dslings/cpp11/17-pod-type-2.cpp rename to src/cpp11/tests/17-pod-type/2.cpp index b3f5558..700cf50 100644 --- a/dslings/cpp11/17-pod-type-2.cpp +++ b/src/cpp11/tests/17-pod-type/2.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/17-pod-type-2.cpp +// file: src/cpp11/tests/17-pod-type/2.cpp // // Exercise/练习: cpp11 | 17 - POD Type | 适配 C 接口的 POD 头部 // @@ -18,10 +18,9 @@ // // d2x checker pod-type -#include +import std; +import d2x; -#include -#include // C 风格的消息头部,仅包含 POD 成员,用于跨语言/跨模块传递 @@ -42,7 +41,7 @@ static MessageHeader g_last_header{}; extern "C" void c_send_header(const void* data, std::size_t size) { // 在真实场景中,这里可能是 C 库/系统调用,这里简化为记录收到的头部 - d2x_assert_eq(size, sizeof(MessageHeader)); + d2x::check_eq(size, sizeof(MessageHeader), "size == sizeof(MessageHeader)"); const auto* header = static_cast(data); g_last_header = *header; } @@ -63,12 +62,11 @@ int main() { send_message_to_c(msg); // 验证 C 接口收到的头部内容是否正确 - d2x_assert_eq(g_last_header.type, msg.type); - d2x_assert_eq(g_last_header.len, static_cast(msg.payload.size())); - d2x_assert_eq(g_last_header.flags, static_cast(0)); - - D2X_WAIT + d2x::check_eq(g_last_header.type, msg.type, "g_last_header.type == msg.type"); + d2x::check_eq(g_last_header.len, static_cast(msg.payload.size()), "g_last_header.len == static_cast(msg.payload.size())"); + d2x::check_eq(g_last_header.flags, static_cast(0), "g_last_header.flags == static_cast(0)"); + d2x::wait(); return 0; } diff --git a/src/cpp14/mcpp.toml b/src/cpp14/mcpp.toml new file mode 100644 index 0000000..4be442e --- /dev/null +++ b/src/cpp14/mcpp.toml @@ -0,0 +1,10 @@ +# cpp14 练习工程。练习 = tests/<章节>/<序号>.cpp,由 mcpp test 直接驱动: +# mcpp test -p src/cpp14 全部练习(进度表) +# mcpp test -p src/cpp14 <子串> 只跑匹配的练习 +[package] +name = "cpp14" +version = "0.1.0" +standard = "c++23" + +[dependencies] +d2x = { path = "../../d2x" } diff --git a/dslings/cpp14/00-generic-lambdas-0.cpp b/src/cpp14/tests/00-generic-lambdas/0.cpp similarity index 56% rename from dslings/cpp14/00-generic-lambdas-0.cpp rename to src/cpp14/tests/00-generic-lambdas/0.cpp index 31ccdd3..d072e0b 100644 --- a/dslings/cpp14/00-generic-lambdas-0.cpp +++ b/src/cpp14/tests/00-generic-lambdas/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp14/00-generic-lambdas-0.cpp +// file: src/cpp14/tests/00-generic-lambdas/0.cpp // // Exercise/练习: cpp14 | 00 - generic lambdas | 泛型 lambda // @@ -19,8 +19,8 @@ // d2x checker generic-lambdas // -#include -#include +import std; +import d2x.harness; int main() { @@ -29,28 +29,27 @@ int main() { return x; }; - d2x_assert_eq(identity(42), 42); - d2x_assert(identity(std::string("hello")) == "hello"); - d2x_assert_eq(identity(3.14), D2X_YOUR_ANSWER); + d2x::check_eq(identity(42), 42, "identity(42) == 42"); + d2x::check(identity(std::string("hello")) == "hello", "identity(std::string(\"hello\")) == \"hello\""); + d2x::check_eq(identity(3.14), D2X_YOUR_ANSWER, "identity(3.14) == D2X_YOUR_ANSWER"); // 1. 泛型 lambda 做比较 auto greater = [](auto a, auto b) { return D2X_YOUR_ANSWER; }; - d2x_assert(greater(5, 3)); - d2x_assert(greater(2.5, 1.2)); - d2x_assert(greater(std::string("z"), std::string("a"))); + d2x::check(greater(5, 3), "greater(5, 3)"); + d2x::check(greater(2.5, 1.2), "greater(2.5, 1.2)"); + d2x::check(greater(std::string("z"), std::string("a")), "greater(std::string(\"z\"), std::string(\"a\"))"); // 2. 推导类型确认 auto get_type_size = [](auto x) { return sizeof(D2X_YOUR_ANSWER); }; - d2x_assert_eq(get_type_size(42), sizeof(int)); - d2x_assert_eq(get_type_size('c'), sizeof(char)); - - D2X_WAIT + d2x::check_eq(get_type_size(42), sizeof(int), "get_type_size(42) == sizeof(int)"); + d2x::check_eq(get_type_size('c'), sizeof(char), "get_type_size('c') == sizeof(char)"); + d2x::wait(); return 0; } diff --git a/dslings/cpp14/00-generic-lambdas-1.cpp b/src/cpp14/tests/00-generic-lambdas/1.cpp similarity index 75% rename from dslings/cpp14/00-generic-lambdas-1.cpp rename to src/cpp14/tests/00-generic-lambdas/1.cpp index e3f0c5b..561be60 100644 --- a/dslings/cpp14/00-generic-lambdas-1.cpp +++ b/src/cpp14/tests/00-generic-lambdas/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp14/00-generic-lambdas-1.cpp +// file: src/cpp14/tests/00-generic-lambdas/1.cpp // // Exercise/练习: cpp14 | 00 - generic lambdas | 泛型 lambda 与 STL 算法 // @@ -19,9 +19,8 @@ // d2x checker generic-lambdas // -#include -#include -#include +import std; +import d2x; int main() { @@ -34,11 +33,11 @@ int main() { }; std::sort(v1.begin(), v1.end(), desc); - d2x_assert_eq(v1[0], 8); - d2x_assert_eq(v1[4], 1); + d2x::check_eq(v1[0], 8, "v1[0] == 8"); + d2x::check_eq(v1[4], 1, "v1[4] == 1"); std::sort(v2.begin(), v2.end(), desc); - d2x_assert_eq(v2[0], D2X_YOUR_ANSWER); + d2x::check_eq(v2[0], D2X_YOUR_ANSWER, "v2[0] == D2X_YOUR_ANSWER"); // 1. 带捕获的泛型 lambda — find_if int threshold = 3; @@ -47,10 +46,10 @@ int main() { }; auto it1 = std::find_if(v1.begin(), v1.end(), above); - d2x_assert(*it1 == D2X_YOUR_ANSWER); + d2x::check(*it1 == D2X_YOUR_ANSWER, "*it1 == D2X_YOUR_ANSWER"); auto it2 = std::find_if(v2.begin(), v2.end(), above); - d2x_assert(*it2 == 8.5); + d2x::check(*it2 == 8.5, "*it2 == 8.5"); // 2. 泛型 lambda 返回 lambda — 函数工厂 auto make_multiplier = [](auto factor) { @@ -58,10 +57,9 @@ int main() { }; auto times2 = make_multiplier(2); - d2x_assert_eq(times2(10), 20); - d2x_assert_eq(times2(0.5), 1.0); - - D2X_WAIT + d2x::check_eq(times2(10), 20, "times2(10) == 20"); + d2x::check_eq(times2(0.5), 1.0, "times2(0.5) == 1.0"); + d2x::wait(); return 0; } diff --git a/src/en/cpp11/mcpp.toml b/src/en/cpp11/mcpp.toml new file mode 100644 index 0000000..805a7ca --- /dev/null +++ b/src/en/cpp11/mcpp.toml @@ -0,0 +1,10 @@ +# cpp11 (en) 练习工程。练习 = tests/<章节>/<序号>.cpp,由 mcpp test 直接驱动: +# mcpp test -p src/en/cpp11 全部练习(进度表) +# mcpp test -p src/en/cpp11 <子串> 只跑匹配的练习 +[package] +name = "en-cpp11" +version = "0.1.0" +standard = "c++23" + +[dependencies] +d2x = { path = "../../../d2x" } diff --git a/dslings/en/cpp11/00-auto-and-decltype-0.cpp b/src/en/cpp11/tests/00-auto-and-decltype/0.cpp similarity index 73% rename from dslings/en/cpp11/00-auto-and-decltype-0.cpp rename to src/en/cpp11/tests/00-auto-and-decltype/0.cpp index 8f2896d..da2e8e2 100644 --- a/dslings/en/cpp11/00-auto-and-decltype-0.cpp +++ b/src/en/cpp11/tests/00-auto-and-decltype/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/00-auto-and-decltype-0.cpp +// file: src/en/cpp11/tests/00-auto-and-decltype/0.cpp // // Exercise: cpp11 | 00 - auto and decltype | Automatic Type Deduction // @@ -18,7 +18,8 @@ // d2x checker auto-and-decltype // -#include +import std; +import d2x; int main() { @@ -35,14 +36,13 @@ int main() { D2X_YOUR_ANSWER c1 = c; D2X_YOUR_ANSWER c2 = c; - d2x_assert_eq(a, a1); - d2x_assert_eq(a1, a2); - d2x_assert_eq(b, b1); - d2x_assert_eq(b1, b2); - d2x_assert_eq(c, c1); - d2x_assert_eq(c1, c2); - - D2X_WAIT + d2x::check_eq(a, a1, "a == a1"); + d2x::check_eq(a1, a2, "a1 == a2"); + d2x::check_eq(b, b1, "b == b1"); + d2x::check_eq(b1, b2, "b1 == b2"); + d2x::check_eq(c, c1, "c == c1"); + d2x::check_eq(c1, c2, "c1 == c2"); + d2x::wait(); return 0; } diff --git a/dslings/en/cpp11/00-auto-and-decltype-1.cpp b/src/en/cpp11/tests/00-auto-and-decltype/1.cpp similarity index 75% rename from dslings/en/cpp11/00-auto-and-decltype-1.cpp rename to src/en/cpp11/tests/00-auto-and-decltype/1.cpp index a3b9a01..1f1c08d 100644 --- a/dslings/en/cpp11/00-auto-and-decltype-1.cpp +++ b/src/en/cpp11/tests/00-auto-and-decltype/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/00-auto-and-decltype-1.cpp +// file: src/en/cpp11/tests/00-auto-and-decltype/1.cpp // // Exercise: cpp11 | 00 - auto and decltype | Expression Type Deduction // @@ -19,7 +19,8 @@ // -#include +import std; +import d2x; int main() { @@ -36,12 +37,11 @@ int main() { D2X_YOUR_ANSWER c1 = 1 + c; D2X_YOUR_ANSWER c2 = 2 + 'a'; - d2x_assert_eq(a2, a + 2 + 1.1); - d2x_assert_eq(b1, a + 0.1); - d2x_assert_eq(c1, 1 + c); - d2x_assert_eq(c2, 2 + 'a'); - - D2X_WAIT + d2x::check_eq(a2, a + 2 + 1.1, "a2 == a + 2 + 1.1"); + d2x::check_eq(b1, a + 0.1, "b1 == a + 0.1"); + d2x::check_eq(c1, 1 + c, "c1 == 1 + c"); + d2x::check_eq(c2, 2 + 'a', "c2 == 2 + 'a'"); + d2x::wait(); return 0; } diff --git a/dslings/en/cpp11/00-auto-and-decltype-2.cpp b/src/en/cpp11/tests/00-auto-and-decltype/2.cpp similarity index 83% rename from dslings/en/cpp11/00-auto-and-decltype-2.cpp rename to src/en/cpp11/tests/00-auto-and-decltype/2.cpp index fb1cffd..664480d 100644 --- a/dslings/en/cpp11/00-auto-and-decltype-2.cpp +++ b/src/en/cpp11/tests/00-auto-and-decltype/2.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/00-auto-and-decltype-2.cpp +// file: src/en/cpp11/tests/00-auto-and-decltype/2.cpp // // Exercise: cpp11 | 00 - auto and decltype | Complex Type Deduction // @@ -18,11 +18,9 @@ // d2x checker auto-and-decltype-2 // -#include +import std; +import d2x; -#include -#include -#include int add_func(int a, int b) { return a + b; @@ -53,10 +51,9 @@ int main() { minus_func }; - d2x_assert_eq(funcVec[0](1, 2), 3); - d2x_assert_eq(funcVec[1](1, 2), -1); - - D2X_WAIT + d2x::check_eq(funcVec[0](1, 2), 3, "funcVec[0](1, 2) == 3"); + d2x::check_eq(funcVec[1](1, 2), -1, "funcVec[1](1, 2) == -1"); + d2x::wait(); return 0; } diff --git a/dslings/en/cpp11/00-auto-and-decltype-3.cpp b/src/en/cpp11/tests/00-auto-and-decltype/3.cpp similarity index 74% rename from dslings/en/cpp11/00-auto-and-decltype-3.cpp rename to src/en/cpp11/tests/00-auto-and-decltype/3.cpp index fb7d426..fbe07b1 100644 --- a/dslings/en/cpp11/00-auto-and-decltype-3.cpp +++ b/src/en/cpp11/tests/00-auto-and-decltype/3.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/00-auto-and-decltype-3.cpp +// file: src/en/cpp11/tests/00-auto-and-decltype/3.cpp // // Exercise: cpp11 | 00 - auto and decltype | Function Return Type Deduction // @@ -18,10 +18,9 @@ // d2x checker auto-and-decltype-3 // -#include +import std; +import d2x; -#include -#include // 3. Function return types @@ -36,11 +35,10 @@ D2X_YOUR_ANSWER minus_func(T1 a, T2 b) -> D2X_YOUR_ANSWER { int main() { - d2x_assert_eq(minus_func(1, 2), -1); - d2x_assert_eq(minus_func(2, 1), 1); - d2x_assert_eq(minus_func(1, 2.1), -1.1); - - D2X_WAIT + d2x::check_eq(minus_func(1, 2), -1, "minus_func(1, 2) == -1"); + d2x::check_eq(minus_func(2, 1), 1, "minus_func(2, 1) == 1"); + d2x::check_eq(minus_func(1, 2.1), -1.1, "minus_func(1, 2.1) == -1.1"); + d2x::wait(); return 0; } diff --git a/dslings/en/cpp11/00-auto-and-decltype-4.cpp b/src/en/cpp11/tests/00-auto-and-decltype/4.cpp similarity index 69% rename from dslings/en/cpp11/00-auto-and-decltype-4.cpp rename to src/en/cpp11/tests/00-auto-and-decltype/4.cpp index f56a15e..e3d9059 100644 --- a/dslings/en/cpp11/00-auto-and-decltype-4.cpp +++ b/src/en/cpp11/tests/00-auto-and-decltype/4.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/00-auto-and-decltype-4.cpp +// file: src/en/cpp11/tests/00-auto-and-decltype/4.cpp // // Exercise: cpp11 | 00 - auto and decltype | Class/Struct Member Type Deduction // @@ -18,9 +18,9 @@ // d2x checker auto-and-decltype-4 // -#include +import std; +import d2x; -#include // 4. Class/Struct member type deduction @@ -38,23 +38,22 @@ int main() { // Type deduction for obj and (obj) type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line // Type deduction for obj.a and (obj.a) type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line // Type deduction for obj.b and (obj.b) type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line - - D2X_WAIT + d2x::check(type_check, "type_check"); type_check = false; // dont change this line + d2x::wait(); return 0; } diff --git a/dslings/en/cpp11/00-auto-and-decltype-5.cpp b/src/en/cpp11/tests/00-auto-and-decltype/5.cpp similarity index 76% rename from dslings/en/cpp11/00-auto-and-decltype-5.cpp rename to src/en/cpp11/tests/00-auto-and-decltype/5.cpp index 90d1664..628371e 100644 --- a/dslings/en/cpp11/00-auto-and-decltype-5.cpp +++ b/src/en/cpp11/tests/00-auto-and-decltype/5.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/00-auto-and-decltype-5.cpp +// file: src/en/cpp11/tests/00-auto-and-decltype/5.cpp // // Exercise: cpp11 | 00 - auto and decltype | const & reference stripping and preservation // @@ -18,9 +18,9 @@ // d2x checker auto-and-decltype-5 // -#include +import std; +import d2x; -#include // 5. const & reference stripping and preservation @@ -35,24 +35,23 @@ int main() { // auto strips top-level const: what does a deduce to? auto a = ci; type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line // auto strips the reference: what does b deduce to? (b is an independent copy of n) auto b = ri; type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line // To keep a const reference const int&: how should cr be declared? D2X_YOUR_ANSWER cr = ci; type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line + d2x::check(type_check, "type_check"); type_check = false; // dont change this line // To preserve the declared type const int exactly: how should d be declared? D2X_YOUR_ANSWER d = ci; type_check = std::is_same::value; - d2x_assert(type_check); type_check = false; // dont change this line - - D2X_WAIT + d2x::check(type_check, "type_check"); type_check = false; // dont change this line + d2x::wait(); return 0; } diff --git a/dslings/en/cpp11/01-default-and-delete-0.cpp b/src/en/cpp11/tests/01-default-and-delete/0.cpp similarity index 88% rename from dslings/en/cpp11/01-default-and-delete-0.cpp rename to src/en/cpp11/tests/01-default-and-delete/0.cpp index 0d03144..f47b3ed 100644 --- a/dslings/en/cpp11/01-default-and-delete-0.cpp +++ b/src/en/cpp11/tests/01-default-and-delete/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/01-default-and-delete-0.cpp +// file: src/en/cpp11/tests/01-default-and-delete/0.cpp // // Exercise: cpp11 | 01 - default and delete | Explicitly specifying constructor generation behavior // @@ -15,9 +15,9 @@ // d2x checker default-and-delete // -#include +import std; +import d2x; -#include // default and delete explicitly control -> compiler default constructor generation behavior struct A { }; @@ -35,7 +35,6 @@ int main() { // Do not directly modify the code in the main function B b; C c(1); - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/01-default-and-delete-1.cpp b/src/en/cpp11/tests/01-default-and-delete/1.cpp similarity index 62% rename from dslings/en/cpp11/01-default-and-delete-1.cpp rename to src/en/cpp11/tests/01-default-and-delete/1.cpp index af05d61..5c5c94b 100644 --- a/dslings/en/cpp11/01-default-and-delete-1.cpp +++ b/src/en/cpp11/tests/01-default-and-delete/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/01-default-and-delete-1.cpp +// file: src/en/cpp11/tests/01-default-and-delete/1.cpp // // Exercise: cpp11 | 01 - default and delete | Non-copyable objects // @@ -15,9 +15,9 @@ // d2x checker default-and-delete-1 // -#include +import std; +import d2x; -#include // Implement std::unique_ptr property: not copyable but movable struct UniquePtr { @@ -32,17 +32,16 @@ int main() { // Do not directly modify the code in the main function // Object cannot be copied/duplicated // std::unique_ptr b = a; // error - d2x_assert(std::is_copy_constructible::value == false); + d2x::check(std::is_copy_constructible::value == false, "std::is_copy_constructible::value == false"); // a = b; // error - d2x_assert(std::is_copy_assignable::value == false); + d2x::check(std::is_copy_assignable::value == false, "std::is_copy_assignable::value == false"); // Object can be moved // std::unique_ptr c = std::move(a); // ok - d2x_assert(std::is_move_constructible::value == true); + d2x::check(std::is_move_constructible::value == true, "std::is_move_constructible::value == true"); // a = std::move(c); // ok - d2x_assert(std::is_move_assignable::value == true); - - D2X_WAIT + d2x::check(std::is_move_assignable::value == true, "std::is_move_assignable::value == true"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/01-default-and-delete-2.cpp b/src/en/cpp11/tests/01-default-and-delete/2.cpp similarity index 85% rename from dslings/en/cpp11/01-default-and-delete-2.cpp rename to src/en/cpp11/tests/01-default-and-delete/2.cpp index 49fc1ad..a6ba9d3 100644 --- a/dslings/en/cpp11/01-default-and-delete-2.cpp +++ b/src/en/cpp11/tests/01-default-and-delete/2.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/01-default-and-delete-2.cpp +// file: src/en/cpp11/tests/01-default-and-delete/2.cpp // // Exercise: cpp11 | 01 - default and delete | Disabling function overloading // @@ -15,9 +15,9 @@ // d2x checker default-and-delete-2 // -#include +import std; +import d2x; -#include void func(int x) { std::cout << "x = " << x << std::endl; @@ -31,7 +31,6 @@ int main() { func(1); // int func(1.1f); // float - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/02-final-and-override-0.cpp b/src/en/cpp11/tests/02-final-and-override/0.cpp similarity index 88% rename from dslings/en/cpp11/02-final-and-override-0.cpp rename to src/en/cpp11/tests/02-final-and-override/0.cpp index a141dd1..c60461a 100644 --- a/dslings/en/cpp11/02-final-and-override-0.cpp +++ b/src/en/cpp11/tests/02-final-and-override/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/02-final-and-override-0.cpp +// file: src/en/cpp11/tests/02-final-and-override/0.cpp // // Exercise: cpp11 | 02 - final and override // @@ -15,10 +15,9 @@ // d2x checker final-and-override // -#include +import std; +import d2x; -#include -#include struct A { virtual void func1() { @@ -51,7 +50,6 @@ int main() { a->func1(); // B::func1() a->func2(); // A::func2() - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/02-final-and-override-1.cpp b/src/en/cpp11/tests/02-final-and-override/1.cpp similarity index 65% rename from dslings/en/cpp11/02-final-and-override-1.cpp rename to src/en/cpp11/tests/02-final-and-override/1.cpp index bad62e2..e4e85c3 100644 --- a/dslings/en/cpp11/02-final-and-override-1.cpp +++ b/src/en/cpp11/tests/02-final-and-override/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/02-final-and-override-1.cpp +// file: src/en/cpp11/tests/02-final-and-override/1.cpp // // Exercise: cpp11 | 02 - final and override // @@ -15,10 +15,9 @@ // d2x checker final-and-override-1 // -#include +import std; +import d2x; -#include -#include struct A { virtual int func1() { @@ -45,14 +44,13 @@ struct C : B { int main() { B final; // Do not directly modify the code in the main function - d2x_assert_eq(final.func1(), 3); // B::func1() - d2x_assert_eq(final.func2(), 4); // B::func2() + d2x::check_eq(final.func1(), 3, "final.func1() == 3"); // B::func1() + d2x::check_eq(final.func2(), 4, "final.func2() == 4"); // B::func2() A *a = &final; - d2x_assert_eq(a->func1(), 3); // B::func1() - d2x_assert_eq(a->func2(), 2); // A::func2() - - D2X_WAIT + d2x::check_eq(a->func1(), 3, "a->func1() == 3"); // B::func1() + d2x::check_eq(a->func2(), 2, "a->func2() == 2"); // A::func2() + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/02-final-and-override-2.cpp b/src/en/cpp11/tests/02-final-and-override/2.cpp similarity index 93% rename from dslings/en/cpp11/02-final-and-override-2.cpp rename to src/en/cpp11/tests/02-final-and-override/2.cpp index 609f684..f3b34d5 100644 --- a/dslings/en/cpp11/02-final-and-override-2.cpp +++ b/src/en/cpp11/tests/02-final-and-override/2.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/02-final-and-override-2.cpp +// file: src/en/cpp11/tests/02-final-and-override/2.cpp // // Exercise: cpp11 | 02 - final and override // @@ -15,10 +15,9 @@ // d2x checker final-and-override-2 // -#include +import std; +import d2x; -#include -#include struct AudioPlayer { // Do not directly modify the AudioPlayer class virtual void play() final { @@ -77,7 +76,6 @@ int main() { // Do not directly modify the code in the main function delete player2; delete player3; - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/03-trailing-return-type.cpp b/src/en/cpp11/tests/03-trailing-return-type/0.cpp similarity index 63% rename from dslings/en/cpp11/03-trailing-return-type.cpp rename to src/en/cpp11/tests/03-trailing-return-type/0.cpp index 7c2d97a..1ec229e 100644 --- a/dslings/en/cpp11/03-trailing-return-type.cpp +++ b/src/en/cpp11/tests/03-trailing-return-type/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/03-trailing-return-type.cpp +// file: src/en/cpp11/tests/03-trailing-return-type/0.cpp // // Exercise: cpp11 | 03 - trailing return type // @@ -14,9 +14,9 @@ // d2x checker trailing-return-type // -#include +import std; +import d2x; -#include int add0(double a, int b) { return a + b; @@ -37,13 +37,12 @@ auto add3 = [](double a, double b) -> D2X_YOUR_ANSWER { int main() { - d2x_assert_eq(add0(1.1, 2), 3); - d2x_assert_eq(add1(1.1, 2), 3); - d2x_assert_eq(add2(1.1, 2), 3.1); - d2x_assert_eq(add2(1, 2.1), 3.1); - d2x_assert_eq(add3(1.1, 2.1), 3); - - D2X_WAIT + d2x::check_eq(add0(1.1, 2), 3, "add0(1.1, 2) == 3"); + d2x::check_eq(add1(1.1, 2), 3, "add1(1.1, 2) == 3"); + d2x::check_eq(add2(1.1, 2), 3.1, "add2(1.1, 2) == 3.1"); + d2x::check_eq(add2(1, 2.1), 3.1, "add2(1, 2.1) == 3.1"); + d2x::check_eq(add3(1.1, 2.1), 3, "add3(1.1, 2.1) == 3"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/04-rvalue-references.cpp b/src/en/cpp11/tests/04-rvalue-references/0.cpp similarity index 55% rename from dslings/en/cpp11/04-rvalue-references.cpp rename to src/en/cpp11/tests/04-rvalue-references/0.cpp index 82da5ff..e34bed1 100644 --- a/dslings/en/cpp11/04-rvalue-references.cpp +++ b/src/en/cpp11/tests/04-rvalue-references/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/04-rvalue-references.cpp +// file: src/en/cpp11/tests/04-rvalue-references/0.cpp // // Exercise: cpp11 | 04 - rvalue references // @@ -14,13 +14,13 @@ // d2x checker rvalue-references // -#include +import std; +import d2x; -#include -#include struct Object; static Object * object_address = nullptr; +static int move_ctor_calls = 0; // 移动构造被调用的次数, 供断言检查 struct Object { int data = 0; @@ -29,7 +29,7 @@ struct Object { object_address = this; } Object(const Object&) { std::cout << "Object(const Object&):" << this << std::endl; } - Object(Object&&) { std::cout << "Object(Object&&):" << this << std::endl; } + Object(Object&&) { ++move_ctor_calls; std::cout << "Object(Object&&):" << this << std::endl; } ~Object() { std::cout << "~Object():" << this << std::endl; } }; @@ -37,8 +37,13 @@ int main() { // Disable compiler optimization { std::cout << "----> Temporary object - rvalue 1" << std::endl; Object(); - std::cout << "----> Temporary object - rvalue 2" << std::endl; - Object obj = Object(); + std::cout << "----> Temporary object - rvalue 2 (named object + std::move)" << std::endl; + // NOTE: `Object obj = Object();` will NOT show a move constructor. + // Since C++17 a prvalue initialises the target directly (guaranteed + // copy elision), and -fno-elide-constructors cannot bring that move + // back. Moving from a named object is the standard-independent way. + Object named; + Object obj = std::move(named); std::cout << "--------Code modifiable area - Start--------" << std::endl; @@ -50,10 +55,12 @@ int main() { // Disable compiler optimization objRef.data = 1; // Modify the value of the extended lifetime temporary object (do not directly modify this line) std::cout << "objRef.data = " << objRef.data << " - " << &objRef << std::endl; - d2x_assert((&objRef == object_address)); + d2x::check((&objRef == object_address), "(&objRef == object_address)"); + // 钉住移动构造确实发生过。教学漂移之所以能静默发生, 正是因为 + // 从前没有任何断言检查它 —— 输出少了一行, 没人发现。 + d2x::check((move_ctor_calls >= 1), "(move_ctor_calls >= 1)"); } - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/05-move-semantics-0.cpp b/src/en/cpp11/tests/05-move-semantics/0.cpp similarity index 83% rename from dslings/en/cpp11/05-move-semantics-0.cpp rename to src/en/cpp11/tests/05-move-semantics/0.cpp index bd488d4..8b6df38 100644 --- a/dslings/en/cpp11/05-move-semantics-0.cpp +++ b/src/en/cpp11/tests/05-move-semantics/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/05-move-semantics-0.cpp +// file: src/en/cpp11/tests/05-move-semantics/0.cpp // // Exercise: cpp11 | 05 - move semantics | Move Construction and Trigger Timing // @@ -14,9 +14,9 @@ // d2x checker move-semantics // -#include +import std; +import d2x; -#include struct Buffer { int *data; @@ -57,20 +57,19 @@ int main() { Buffer buff2(std::move(buff1)); auto buff2DataPtr = buff2.data_ptr(); - d2x_assert(buff1DataPtr == buff2DataPtr); + d2x::check(buff1DataPtr == buff2DataPtr, "buff1DataPtr == buff2DataPtr"); Buffer buff3 = buff2; auto buff3DataPtr = buff3.data_ptr(); - d2x_assert(buff2DataPtr == buff3DataPtr); + d2x::check(buff2DataPtr == buff3DataPtr, "buff2DataPtr == buff3DataPtr"); Buffer buff4 = process(buff3); auto buff4DataPtr = buff4.data_ptr(); - d2x_assert(buff3DataPtr == buff4DataPtr); + d2x::check(buff3DataPtr == buff4DataPtr, "buff3DataPtr == buff4DataPtr"); } - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/05-move-semantics-1.cpp b/src/en/cpp11/tests/05-move-semantics/1.cpp similarity index 87% rename from dslings/en/cpp11/05-move-semantics-1.cpp rename to src/en/cpp11/tests/05-move-semantics/1.cpp index 0589a4c..11b4e2c 100644 --- a/dslings/en/cpp11/05-move-semantics-1.cpp +++ b/src/en/cpp11/tests/05-move-semantics/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/05-move-semantics-1.cpp +// file: src/en/cpp11/tests/05-move-semantics/1.cpp // // Exercise: cpp11 | 05 - move semantics | Move Assignment and Trigger Timing // @@ -14,9 +14,9 @@ // d2x checker move-semantics // -#include +import std; +import d2x; -#include static int move_assignment_counter = 0; @@ -80,21 +80,20 @@ int main() { // No compiler optimization buff1 = Buffer(); // Case 1: Temporary object assignment - d2x_assert_eq(move_assignment_counter, 1); + d2x::check_eq(move_assignment_counter, 1, "move_assignment_counter == 1"); Buffer buff2; buff2 = process(buff1); // Case 2: Intermediate object assignment - d2x_assert_eq(move_assignment_counter, 2); + d2x::check_eq(move_assignment_counter, 2, "move_assignment_counter == 2"); buff2 = buff1; // Case 3: Explicit move assignment - d2x_assert_eq(move_assignment_counter, 3); + d2x::check_eq(move_assignment_counter, 3, "move_assignment_counter == 3"); } - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/05-move-semantics-2.cpp b/src/en/cpp11/tests/05-move-semantics/2.cpp similarity index 85% rename from dslings/en/cpp11/05-move-semantics-2.cpp rename to src/en/cpp11/tests/05-move-semantics/2.cpp index cffbadb..847db82 100644 --- a/dslings/en/cpp11/05-move-semantics-2.cpp +++ b/src/en/cpp11/tests/05-move-semantics/2.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/05-move-semantics-2.cpp +// file: src/en/cpp11/tests/05-move-semantics/2.cpp // // Exercise: cpp11 | 05 - move semantics | Moving resources not objects // @@ -14,9 +14,9 @@ // d2x checker move-semantics-2 // -#include +import std; +import d2x; -#include struct Buffer { int *data; @@ -72,13 +72,12 @@ int main() { // Move semantics - Demonstrating moving resources not objects Buffer b2 = b1; // std::move(b1); - d2x_assert(&b1 != &b2); // b1 and b2 are different objects - d2x_assert(old_b1_data_ptr == b2.data_ptr()); - d2x_assert(b1.data_ptr() == nullptr); // b1's resources have been moved + d2x::check(&b1 != &b2, "&b1 != &b2"); // b1 and b2 are different objects + d2x::check(old_b1_data_ptr == b2.data_ptr(), "old_b1_data_ptr == b2.data_ptr()"); + d2x::check(b1.data_ptr() == nullptr, "b1.data_ptr() == nullptr"); // b1's resources have been moved } - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/06-scoped-enums-0.cpp b/src/en/cpp11/tests/06-scoped-enums/0.cpp similarity index 78% rename from dslings/en/cpp11/06-scoped-enums-0.cpp rename to src/en/cpp11/tests/06-scoped-enums/0.cpp index c77c40a..17980c1 100644 --- a/dslings/en/cpp11/06-scoped-enums-0.cpp +++ b/src/en/cpp11/tests/06-scoped-enums/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/06-scoped-enums-0.cpp +// file: src/en/cpp11/tests/06-scoped-enums/0.cpp // // Exercise: cpp11 | 06 - scoped enums | Traditional enum type potential issues // @@ -14,9 +14,9 @@ // d2x checker scoped-enums // -#include +import std; +import d2x; -#include enum Color { RED, @@ -36,20 +36,19 @@ int main() { Color color = RED; Fruit fruit = Apple; - d2x_assert_eq(color, RED); - d2x_assert_eq(fruit, Apple); + d2x::check_eq(color, RED, "color == RED"); + d2x::check_eq(fruit, Apple, "fruit == Apple"); // 2. Syntactically correct, but logically wrong type matching if (color == Apple) { // Do not delete this line of code // Code will run here - D2X_WAIT + d2x::wait(); } if (fruit == RED) { - D2X_WAIT + d2x::wait(); } - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/06-scoped-enums-1.cpp b/src/en/cpp11/tests/06-scoped-enums/1.cpp similarity index 69% rename from dslings/en/cpp11/06-scoped-enums-1.cpp rename to src/en/cpp11/tests/06-scoped-enums/1.cpp index eddfdb6..3f4b207 100644 --- a/dslings/en/cpp11/06-scoped-enums-1.cpp +++ b/src/en/cpp11/tests/06-scoped-enums/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/06-scoped-enums-1.cpp +// file: src/en/cpp11/tests/06-scoped-enums/1.cpp // // Exercise: cpp11 | 06 - scoped enums | Scoped enum type basic usage // @@ -14,9 +14,9 @@ // d2x checker scoped-enums-1 // -#include +import std; +import d2x; -#include enum class Color { RED, @@ -37,12 +37,12 @@ int main() { Color color = Color::ORANGE; Fruit fruit = Fruit::ORANGE; - d2x_assert(color == Color::ORANGE); - d2x_assert(fruit == Fruit::ORANGE); + d2x::check(color == Color::ORANGE, "color == Color::ORANGE"); + d2x::check(fruit == Fruit::ORANGE, "fruit == Fruit::ORANGE"); // 2. Type safety: Prevent comparison between different enum type values if (color == Fruit::ORANGE) { // Use Color type to fix compilation error - d2x_assert(color == Color::ORANGE); + d2x::check(color == Color::ORANGE, "color == Color::ORANGE"); } // 3. Type checking: By default, scoped enum type values cannot be implicitly converted @@ -56,8 +56,8 @@ int main() { ORANGE // Orange color }; - d2x_assert_eq(sizeof(Color), sizeof(int)); // Default type is int - d2x_assert_eq(sizeof(Color8Bit), sizeof(int8_t)); // Can customize type int8_t + d2x::check_eq(sizeof(Color), sizeof(int), "sizeof(Color) == sizeof(int)"); // Default type is int + d2x::check_eq(sizeof(Color8Bit), sizeof(std::int8_t), "sizeof(Color8Bit) == sizeof(std::int8_t)"); // Can customize type std::int8_t // 5. Custom starting value: By default, scoped enum type values start from 0 and increment downward enum class ErrorCode : int { @@ -67,9 +67,8 @@ int main() { ERROR_3 }; - d2x_assert_eq(static_cast(ErrorCode::ERROR_3), 3); - - D2X_WAIT + d2x::check_eq(static_cast(ErrorCode::ERROR_3), 3, "static_cast(ErrorCode::ERROR_3) == 3"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/07-constexpr-0.cpp b/src/en/cpp11/tests/07-constexpr/0.cpp similarity index 85% rename from dslings/en/cpp11/07-constexpr-0.cpp rename to src/en/cpp11/tests/07-constexpr/0.cpp index b381c59..a68b340 100644 --- a/dslings/en/cpp11/07-constexpr-0.cpp +++ b/src/en/cpp11/tests/07-constexpr/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/07-constexpr-0.cpp +// file: src/en/cpp11/tests/07-constexpr/0.cpp // // Exercise: cpp11 | 07 - constexpr | Compile-time computation basics: Difference between constexpr and const // @@ -14,9 +14,9 @@ // d2x checker constexpr // -#include +import std; +import d2x; -#include int sum_for_1_to(int n) { return n == 1 ? 1 : n + sum_for_1_to(n - 1); @@ -34,10 +34,9 @@ int main() { { // 2. Compile-time computation basics constexpr int s = sum_for_1_to(4); - d2x_assert_eq(s, 1 + 2 + 3 + 4); + d2x::check_eq(s, 1 + 2 + 3 + 4, "s == 1 + 2 + 3 + 4"); } - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/07-constexpr-1.cpp b/src/en/cpp11/tests/07-constexpr/1.cpp similarity index 94% rename from dslings/en/cpp11/07-constexpr-1.cpp rename to src/en/cpp11/tests/07-constexpr/1.cpp index 47156ee..1fd5acc 100644 --- a/dslings/en/cpp11/07-constexpr-1.cpp +++ b/src/en/cpp11/tests/07-constexpr/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/07-constexpr-1.cpp +// file: src/en/cpp11/tests/07-constexpr/1.cpp // // Exercise: cpp11 | 07 - constexpr | Compile-time computation application examples // @@ -14,9 +14,9 @@ // d2x checker constexpr // -#include +import std; +import d2x; -#include template struct Sum { @@ -67,7 +67,6 @@ int main() { constexpr double sin30 = mysin(30.0); std::cout << "mysin(30): " << sin30 << " " << std::endl; - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/08-literal-type-0.cpp b/src/en/cpp11/tests/08-literal-type/0.cpp similarity index 91% rename from dslings/en/cpp11/08-literal-type-0.cpp rename to src/en/cpp11/tests/08-literal-type/0.cpp index a6c92e8..0a8b098 100644 --- a/dslings/en/cpp11/08-literal-type-0.cpp +++ b/src/en/cpp11/tests/08-literal-type/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/08-literal-type-0.cpp +// file: src/en/cpp11/tests/08-literal-type/0.cpp // // Exercise: cpp11 | 08 - literal type | What are literal types // @@ -14,11 +14,9 @@ // d2x checker literal-type-0 // -#include +import std; +import d2x; -#include -#include -#include constexpr char compile_time_compute(char c, int a) { return a + c; @@ -54,7 +52,6 @@ int main() { std::cout << "1 + 2 + 3 = " << sum << std::endl; - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/08-literal-type-1.cpp b/src/en/cpp11/tests/08-literal-type/1.cpp similarity index 87% rename from dslings/en/cpp11/08-literal-type-1.cpp rename to src/en/cpp11/tests/08-literal-type/1.cpp index 5f3d785..b75ad25 100644 --- a/dslings/en/cpp11/08-literal-type-1.cpp +++ b/src/en/cpp11/tests/08-literal-type/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/08-literal-type-1.cpp +// file: src/en/cpp11/tests/08-literal-type/1.cpp // // Exercise: cpp11 | 08 - literal type | Custom literal types // @@ -14,9 +14,9 @@ // d2x checker literal-type-1 // -#include +import std; +import d2x; -#include struct Vector { int x, y; @@ -34,7 +34,6 @@ int main() { std::cout << "[ " << v3.x << ", " << v3.y << " ]" << std::endl; - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/09-list-initialization-0.cpp b/src/en/cpp11/tests/09-list-initialization/0.cpp similarity index 61% rename from dslings/en/cpp11/09-list-initialization-0.cpp rename to src/en/cpp11/tests/09-list-initialization/0.cpp index 3fe3da5..6cbed68 100644 --- a/dslings/en/cpp11/09-list-initialization-0.cpp +++ b/src/en/cpp11/tests/09-list-initialization/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/09-list-initialization-0.cpp +// file: src/en/cpp11/tests/09-list-initialization/0.cpp // // Exercise: cpp11 | 09 - list initialization | Narrowing checks // @@ -15,19 +15,19 @@ // d2x checker list-initialization // -#include +import std; +import d2x; -#include int main() { int a1 = 1.1; - d2x_assert_eq(a1, 1); + d2x::check_eq(a1, 1, "a1 == 1"); int a2 = 1.1; int a3 = { 1.1 }; - d2x_assert_eq(a2, 1); - d2x_assert_eq(a3, 1); + d2x::check_eq(a2, 1, "a2 == 1"); + d2x::check_eq(a3, 1, "a3 == 1"); double b1 { 1.1 }; constexpr double c1 { 2.2 }; @@ -35,18 +35,17 @@ int main() { int b2 { b1 }; int c2 { c1 }; - d2x_assert_eq(b2, 1); - d2x_assert_eq(c2, 2); + d2x::check_eq(b2, 1, "b2 == 1"); + d2x::check_eq(c2, 2, "c2 == 2"); int arr1[] = { 1, 2.2, 3 }; - d2x_assert_eq(arr1[1], 2); + d2x::check_eq(arr1[1], 2, "arr1[1] == 2"); int arr2[4] { 1, b1, c1 }; - d2x_assert_eq(arr2[1], 1); - d2x_assert_eq(arr2[2], 2); - d2x_assert_eq(arr2[3], 0); - - D2X_WAIT + d2x::check_eq(arr2[1], 1, "arr2[1] == 1"); + d2x::check_eq(arr2[2], 2, "arr2[2] == 2"); + d2x::check_eq(arr2[3], 0, "arr2[3] == 0"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/09-list-initialization-1.cpp b/src/en/cpp11/tests/09-list-initialization/1.cpp similarity index 81% rename from dslings/en/cpp11/09-list-initialization-1.cpp rename to src/en/cpp11/tests/09-list-initialization/1.cpp index 1245e9b..7a5a5f2 100644 --- a/dslings/en/cpp11/09-list-initialization-1.cpp +++ b/src/en/cpp11/tests/09-list-initialization/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/09-list-initialization-1.cpp +// file: src/en/cpp11/tests/09-list-initialization/1.cpp // // Exercise: cpp11 | 09 - list initialization | Default initialization syntax pitfalls // @@ -15,9 +15,9 @@ // d2x checker list-initialization // -#include +import std; +import d2x; -#include struct Object { Object() { @@ -35,10 +35,9 @@ int main() { Object obj1(); Object obj2(2); - d2x_assert_eq(obj1.x, 0); - d2x_assert_eq(obj2.x, 2); - - D2X_WAIT + d2x::check_eq(obj1.x, 0, "obj1.x == 0"); + d2x::check_eq(obj2.x, 2, "obj2.x == 2"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/09-list-initialization-2.cpp b/src/en/cpp11/tests/09-list-initialization/2.cpp similarity index 74% rename from dslings/en/cpp11/09-list-initialization-2.cpp rename to src/en/cpp11/tests/09-list-initialization/2.cpp index 5914394..2e245e3 100644 --- a/dslings/en/cpp11/09-list-initialization-2.cpp +++ b/src/en/cpp11/tests/09-list-initialization/2.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/09-list-initialization-2.cpp +// file: src/en/cpp11/tests/09-list-initialization/2.cpp // // Exercise: cpp11 | 09 - list initialization | Container list initialization // @@ -16,11 +16,9 @@ // d2x checker list-initialization // -#include +import std; +import d2x; -#include -#include -#include class MyVector { int mSize; @@ -36,16 +34,15 @@ class MyVector { int main() { std::vector vec1 = { 1, 2, 3 }; - d2x_assert_eq(vec1.size(), 3); + d2x::check_eq(vec1.size(), 3, "vec1.size() == 3"); std::vector vec2 { 1, 2, 3, 4, 5 }; - d2x_assert_eq(vec2.size(), 5); + d2x::check_eq(vec2.size(), 5, "vec2.size() == 5"); MyVector myVec1 = { 1, 2, 3 }; - d2x_assert_eq(myVec1.size(), 3); + d2x::check_eq(myVec1.size(), 3, "myVec1.size() == 3"); MyVector myVec2 { 1, 2, 3, 4, 5 }; - d2x_assert_eq(myVec2.size(), 5); - - D2X_WAIT + d2x::check_eq(myVec2.size(), 5, "myVec2.size() == 5"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/09-list-initialization-3.cpp b/src/en/cpp11/tests/09-list-initialization/3.cpp similarity index 82% rename from dslings/en/cpp11/09-list-initialization-3.cpp rename to src/en/cpp11/tests/09-list-initialization/3.cpp index 416c660..82b80d1 100644 --- a/dslings/en/cpp11/09-list-initialization-3.cpp +++ b/src/en/cpp11/tests/09-list-initialization/3.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/09-list-initialization-3.cpp +// file: src/en/cpp11/tests/09-list-initialization/3.cpp // // Exercise: cpp11 | 09 - list initialization | Precautions // @@ -16,11 +16,9 @@ // d2x checker list-initialization // -#include +import std; +import d2x; -#include -#include -#include class MyVector { int mSize; @@ -73,16 +71,15 @@ int main() { Point p2 {3, 4}; MyVector vec1(1); - d2x_assert_eq(vec1.size(), 1); + d2x::check_eq(vec1.size(), 1, "vec1.size() == 1"); MyVector vec2 { 1 }; - d2x_assert_eq(vec2.size(), 1); + d2x::check_eq(vec2.size(), 1, "vec2.size() == 1"); MyVector vec3(1, 10); - d2x_assert_eq(vec3.size(), 10); + d2x::check_eq(vec3.size(), 10, "vec3.size() == 10"); MyVector vec4 { 1, 10 }; - d2x_assert_eq(vec4.size(), 10); - - D2X_WAIT + d2x::check_eq(vec4.size(), 10, "vec4.size() == 10"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/10-delegating-constructors-0.cpp b/src/en/cpp11/tests/10-delegating-constructors/0.cpp similarity index 70% rename from dslings/en/cpp11/10-delegating-constructors-0.cpp rename to src/en/cpp11/tests/10-delegating-constructors/0.cpp index b79d40a..5818f47 100644 --- a/dslings/en/cpp11/10-delegating-constructors-0.cpp +++ b/src/en/cpp11/tests/10-delegating-constructors/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/10-delegating-constructors-0.cpp +// file: src/en/cpp11/tests/10-delegating-constructors/0.cpp // // Exercise: cpp11 | 10 - delegating constructors | Delegating Constructors // @@ -15,10 +15,9 @@ // d2x checker delegating-constructors // -#include +import std; +import d2x; -#include -#include static int construction_counter { 0 }; @@ -33,7 +32,7 @@ class Account { name = "momo"; coin = "0元"; - D2X_DONT_DELETE_THIS(construction_counter++); + d2x::dont_delete_this(construction_counter++); } Account(std::string id_, std::string name_) { @@ -41,7 +40,7 @@ class Account { name = name_; coin = "0元"; - D2X_DONT_DELETE_THIS(construction_counter++); + d2x::dont_delete_this(construction_counter++); } Account(std::string id_, std::string name_, int coin_) { @@ -49,7 +48,7 @@ class Account { name = name_; coin = std::to_string(coin_) + "元"; - D2X_DONT_DELETE_THIS(construction_counter++); + d2x::dont_delete_this(construction_counter++); } std::string to_string() const { @@ -60,26 +59,23 @@ class Account { int main() { // Do not modify the code in the main function Account a1 { "1111" }; - d2x_assert_eq(construction_counter, 3); + d2x::check_eq(construction_counter, 3, "construction_counter == 3"); std::cout << a1.to_string() << std::endl; Account a2 { "2222", "wukong" }; - d2x_assert_eq(construction_counter, 5); + d2x::check_eq(construction_counter, 5, "construction_counter == 5"); std::cout << a2.to_string() << std::endl; Account a3 { "3333", "mcpp", 100 }; - d2x_assert_eq(construction_counter, 6); + d2x::check_eq(construction_counter, 6, "construction_counter == 6"); std::cout << a3.to_string() << std::endl; Account gi { "0000", "GImpact", 648 }; std::cout << gi.to_string() << std::endl; - d2x_assert( - gi.to_string() == - "Account { id: 0000, name: GImpact, coin: 648原石 }" - ); - - D2X_WAIT + d2x::check(gi.to_string() == + "Account { id: 0000, name: GImpact, coin: 648原石 }", "gi.to_string() == \"Account { id: 0000, name: GImpact, coin: 648原石 }\""); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/10-delegating-constructors-1.cpp b/src/en/cpp11/tests/10-delegating-constructors/1.cpp similarity index 85% rename from dslings/en/cpp11/10-delegating-constructors-1.cpp rename to src/en/cpp11/tests/10-delegating-constructors/1.cpp index 4843fd2..c2a6398 100644 --- a/dslings/en/cpp11/10-delegating-constructors-1.cpp +++ b/src/en/cpp11/tests/10-delegating-constructors/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/10-delegating-constructors-1.cpp +// file: src/en/cpp11/tests/10-delegating-constructors/1.cpp // // Exercise: cpp11 | 10 - delegating constructors | Delegating Constructors Precautions // @@ -15,10 +15,9 @@ // d2x checker delegating-constructors // -#include +import std; +import d2x; -#include -#include struct Object { // Do not modify the code of this class static int construction_counter; @@ -77,16 +76,15 @@ int main() { // Do not modify the code in the main function Account a1 { "1111", "hello" }; std::cout << a1.to_string() << std::endl; - d2x_assert(a1.get_id() == "1111"); + d2x::check(a1.get_id() == "1111", "a1.get_id() == \"1111\""); Object::construction_counter = 0; Account a2 { "2222", "d2learn", 100 }; std::cout << a2.to_string() << std::endl; - d2x_assert(a2.get_object_name() == "d2learn"); - d2x_assert_eq(Object::construction_counter, 1); - - D2X_WAIT + d2x::check(a2.get_object_name() == "d2learn", "a2.get_object_name() == \"d2learn\""); + d2x::check_eq(Object::construction_counter, 1, "Object::construction_counter == 1"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/11-inherited-constructors-0.cpp b/src/en/cpp11/tests/11-inherited-constructors/0.cpp similarity index 92% rename from dslings/en/cpp11/11-inherited-constructors-0.cpp rename to src/en/cpp11/tests/11-inherited-constructors/0.cpp index 4daf5f1..019e51e 100644 --- a/dslings/en/cpp11/11-inherited-constructors-0.cpp +++ b/src/en/cpp11/tests/11-inherited-constructors/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/11-inherited-constructors-0.cpp +// file: src/en/cpp11/tests/11-inherited-constructors/0.cpp // // Exercise: cpp11 | 11 - inherited constructors | Inherited Constructors // @@ -15,10 +15,9 @@ // d2x checker inherited-constructors // -#include +import std; +import d2x; -#include -#include class ObjectBase { public: @@ -66,7 +65,6 @@ int main() { // Do not directly modify the code in the main function a1.tips_a(); b1.tips_b(); - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/11-inherited-constructors-1.cpp b/src/en/cpp11/tests/11-inherited-constructors/1.cpp similarity index 63% rename from dslings/en/cpp11/11-inherited-constructors-1.cpp rename to src/en/cpp11/tests/11-inherited-constructors/1.cpp index 95c63e1..81a6853 100644 --- a/dslings/en/cpp11/11-inherited-constructors-1.cpp +++ b/src/en/cpp11/tests/11-inherited-constructors/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/11-inherited-constructors-1.cpp +// file: src/en/cpp11/tests/11-inherited-constructors/1.cpp // // Exercise: cpp11 | 11 - inherited constructors | Inherited Constructors for Function Extension // @@ -15,10 +15,9 @@ // d2x checker inherited-constructors // -#include +import std; +import d2x; -#include -#include class Student { // Do not directly modify the code in the Student class protected: @@ -62,35 +61,34 @@ int main() { // Do not directly modify the code in the main function { // Basic test StudentTest studentTest; - d2x_assert(studentTest.age_valid() == true); - d2x_assert(studentTest.score_valid() == true); - d2x_assert(studentTest.to_string() == "{001, 张三, 18, 0}"); + d2x::check(studentTest.age_valid() == true, "studentTest.age_valid() == true"); + d2x::check(studentTest.score_valid() == true, "studentTest.score_valid() == true"); + d2x::check(studentTest.to_string() == "{001, 张三, 18, 0}", "studentTest.to_string() == \"{001, 张三, 18, 0}\""); } { // Boundary test StudentTest studentTest("002", "张三", 201); - d2x_assert(studentTest.score_valid() == true); - d2x_assert(studentTest.age_valid() == false); + d2x::check(studentTest.score_valid() == true, "studentTest.score_valid() == true"); + d2x::check(studentTest.age_valid() == false, "studentTest.age_valid() == false"); studentTest.set_score(101); studentTest.set_age(200); - d2x_assert(studentTest.score_valid() == false); - d2x_assert(studentTest.age_valid() == true); + d2x::check(studentTest.score_valid() == false, "studentTest.score_valid() == false"); + d2x::check(studentTest.age_valid() == true, "studentTest.age_valid() == true"); studentTest.set_score(0); studentTest.set_age(1); - d2x_assert(studentTest.score_valid() == true); - d2x_assert(studentTest.age_valid() == true); + d2x::check(studentTest.score_valid() == true, "studentTest.score_valid() == true"); + d2x::check(studentTest.age_valid() == true, "studentTest.age_valid() == true"); studentTest.set_score(-1); studentTest.set_age(0); - d2x_assert(studentTest.score_valid() == false); - d2x_assert(studentTest.age_valid() == false); + d2x::check(studentTest.score_valid() == false, "studentTest.score_valid() == false"); + d2x::check(studentTest.age_valid() == false, "studentTest.age_valid() == false"); } - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/11-inherited-constructors-2.cpp b/src/en/cpp11/tests/11-inherited-constructors/2.cpp similarity index 80% rename from dslings/en/cpp11/11-inherited-constructors-2.cpp rename to src/en/cpp11/tests/11-inherited-constructors/2.cpp index 48133a9..689abab 100644 --- a/dslings/en/cpp11/11-inherited-constructors-2.cpp +++ b/src/en/cpp11/tests/11-inherited-constructors/2.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/11-inherited-constructors-2.cpp +// file: src/en/cpp11/tests/11-inherited-constructors/2.cpp // // Exercise: cpp11 | 11 - inherited constructors | Inherited Constructors in Generic Decorator Applications // @@ -16,10 +16,9 @@ // d2x checker inherited-constructors // -#include +import std; +import d2x; -#include -#include struct Point { double mX, mY; @@ -54,13 +53,13 @@ int main() { auto p11 = p1; std::cout << "p11: " << p11.to_string() << std::endl; - d2x_assert_eq(p1.mX, p11.mX); - d2x_assert_eq(p1.mY, p11.mY); + d2x::check_eq(p1.mX, p11.mX, "p1.mX == p11.mX"); + d2x::check_eq(p1.mY, p11.mY, "p1.mY == p11.mY"); decltype(p2) p22 = p2; // by std::move? std::cout << "p22: " << p22.to_string() << std::endl; - d2x_assert_eq(p2.mX, p22.mX); - d2x_assert_eq(p2.mY, p22.mY); + d2x::check_eq(p2.mX, p22.mX, "p2.mX == p22.mX"); + d2x::check_eq(p2.mY, p22.mY, "p2.mY == p22.mY"); NoMove p3(3, 3); std::cout << "p3: " << p3.to_string() << std::endl; @@ -68,10 +67,9 @@ int main() { NoMove p33(0, 0); p33 = std::move(p3); // by copy? std::cout << "p33: " << p33.to_string() << std::endl; - d2x_assert_eq(p3.mX, p33.mX); - d2x_assert_eq(p3.mY, p33.mY); - - D2X_WAIT + d2x::check_eq(p3.mX, p33.mX, "p3.mX == p33.mX"); + d2x::check_eq(p3.mY, p33.mY, "p3.mY == p33.mY"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/12-nullptr-0.cpp b/src/en/cpp11/tests/12-nullptr/0.cpp similarity index 67% rename from dslings/en/cpp11/12-nullptr-0.cpp rename to src/en/cpp11/tests/12-nullptr/0.cpp index 7cf0132..dd0bb1a 100644 --- a/dslings/en/cpp11/12-nullptr-0.cpp +++ b/src/en/cpp11/tests/12-nullptr/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/en/cpp11/12-nullptr-0.cpp +// file: src/en/cpp11/tests/12-nullptr/0.cpp // // Exercise: cpp11 | 12 - nullptr | Pointer Literal - Basic Usage // @@ -17,9 +17,10 @@ // d2x checker nullptr // -#include +#include // NULL 宏是这一课的教具,import std 不带宏 +import std; +import d2x; -#include int main() { @@ -28,13 +29,13 @@ int main() { int* ptr2 = NULL; // Fix here, add correct type int* ptr3 = 0; // Not recommended traditional usage - d2x_assert(ptr1 == nullptr); - d2x_assert(ptr2 == nullptr); - d2x_assert(ptr3 == nullptr); + d2x::check(ptr1 == nullptr, "ptr1 == nullptr"); + d2x::check(ptr2 == nullptr, "ptr2 == nullptr"); + d2x::check(ptr3 == nullptr, "ptr3 == nullptr"); // 2. Type of nullptr bool ok = std::is_same::value; - d2x_assert(ok); + d2x::check(ok, "ok"); // 3. Use nullptr for pointer comparison int value = 42; @@ -42,7 +43,7 @@ int main() { if (ptr4 != nullptr) { *ptr4 = D2X_YOUR_ANSWER; - d2x_assert_eq(*ptr4, 2233); + d2x::check_eq(*ptr4, 2233, "*ptr4 == 2233"); } // 4. Different types of pointers can all use nullptr @@ -50,11 +51,10 @@ int main() { char* cptr = nullptr void* vptr = nullptr; - d2x_assert(dptr == nullptr); - d2x_assert(cptr == nullptr); - d2x_assert(vptr == nullptr); - - D2X_WAIT + d2x::check(dptr == nullptr, "dptr == nullptr"); + d2x::check(cptr == nullptr, "cptr == nullptr"); + d2x::check(vptr == nullptr, "vptr == nullptr"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/12-nullptr-1.cpp b/src/en/cpp11/tests/12-nullptr/1.cpp similarity index 71% rename from dslings/en/cpp11/12-nullptr-1.cpp rename to src/en/cpp11/tests/12-nullptr/1.cpp index 274820e..c098af2 100644 --- a/dslings/en/cpp11/12-nullptr-1.cpp +++ b/src/en/cpp11/tests/12-nullptr/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/en/cpp11/12-nullptr-1.cpp +// file: src/en/cpp11/tests/12-nullptr/1.cpp // // Exercise: cpp11 | 12 - nullptr | Pointer Literal - Function Overloading // @@ -17,7 +17,9 @@ // d2x checker nullptr // -#include +#include // NULL 宏是这一课的教具,import std 不带宏 +import std; +import d2x; bool process_int_called = false; bool process_ptr_called = false; @@ -47,12 +49,11 @@ int main() { display(NULL); process(NULL); - d2x_assert(process_int_called); - d2x_assert(display_int_called); - d2x_assert(display_ptr_called); - d2x_assert(display_ptr_called); - - D2X_WAIT + d2x::check(process_int_called, "process_int_called"); + d2x::check(display_int_called, "display_int_called"); + d2x::check(display_ptr_called, "display_ptr_called"); + d2x::check(display_ptr_called, "display_ptr_called"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/12-nullptr-2.cpp b/src/en/cpp11/tests/12-nullptr/2.cpp similarity index 88% rename from dslings/en/cpp11/12-nullptr-2.cpp rename to src/en/cpp11/tests/12-nullptr/2.cpp index 05750bf..abc89c7 100644 --- a/dslings/en/cpp11/12-nullptr-2.cpp +++ b/src/en/cpp11/tests/12-nullptr/2.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/en/cpp11/12-nullptr-2.cpp +// file: src/en/cpp11/tests/12-nullptr/2.cpp // // Exercise: cpp11 | 12 - nullptr | Pointer Literal - Template Programming // @@ -17,8 +17,9 @@ // d2x checker nullptr // -#include -#include +#include // NULL 宏是这一课的教具,import std 不带宏 +import std; +import d2x; // Template function example template @@ -44,7 +45,6 @@ int main() { processPointer(clone(nullptr)); processPointer(clone(nullptr)); - D2X_WAIT - + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/13-long-long-0.cpp b/src/en/cpp11/tests/13-long-long/0.cpp similarity index 78% rename from dslings/en/cpp11/13-long-long-0.cpp rename to src/en/cpp11/tests/13-long-long/0.cpp index b433fc2..bda0fe8 100644 --- a/dslings/en/cpp11/13-long-long-0.cpp +++ b/src/en/cpp11/tests/13-long-long/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/en/cpp11/13-long-long-0.cpp +// file: src/en/cpp11/tests/13-long-long/0.cpp // // Exercise: cpp11 | 13 - long long | 64-bit Integer Type - Basic Usage // @@ -17,9 +17,9 @@ // d2x checker long-long // -#include +import std; +import d2x; -#include int main() { @@ -29,7 +29,7 @@ int main() { // 2. Integer representation range unsigned int uVal1 = 18446744073709551615; - d2x_assert_eq(uVal1, 18446744073709551615ULL); + d2x::check_eq(uVal1, 18446744073709551615ULL, "uVal1 == 18446744073709551615ULL"); // 3. Type deduction and literals // Fix the declarations below to let auto correctly deduce the types @@ -39,10 +39,9 @@ int main() { bool is_longlong = std::is_same::value; bool is_ulonglong = std::is_same::value; - d2x_assert(is_longlong == true); - d2x_assert(is_ulonglong == true); - - D2X_WAIT + d2x::check(is_longlong == true, "is_longlong == true"); + d2x::check(is_ulonglong == true, "is_ulonglong == true"); + d2x::wait(); return 0; } diff --git a/dslings/en/cpp11/13-long-long-1.cpp b/src/en/cpp11/tests/13-long-long/1.cpp similarity index 65% rename from dslings/en/cpp11/13-long-long-1.cpp rename to src/en/cpp11/tests/13-long-long/1.cpp index 8bf569a..fe16571 100644 --- a/dslings/en/cpp11/13-long-long-1.cpp +++ b/src/en/cpp11/tests/13-long-long/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/en/cpp11/13-long-long-1.cpp +// file: src/en/cpp11/tests/13-long-long/1.cpp // // Exercise: cpp11 | 13 - long long | 64-bit Integer Type - Large Number Applications and Boundary Values // @@ -17,9 +17,9 @@ // d2x checker long-long // -#include +import std; +import d2x; -#include int main() { @@ -29,16 +29,15 @@ int main() { auto minLL = std::numeric_limits::min(); auto maxULL = std::numeric_limits::max(); - d2x_assert_eq(maxInt, 2147483647); - d2x_assert_eq(maxLL, 9223372036854775807LL); - d2x_assert_eq(minLL, -9223372036854775807LL - 1); - d2x_assert_eq(maxULL, 18446744073709551615ULL); + d2x::check_eq(maxInt, 2147483647, "maxInt == 2147483647"); + d2x::check_eq(maxLL, 9223372036854775807LL, "maxLL == 9223372036854775807LL"); + d2x::check_eq(minLL, -9223372036854775807LL - 1, "minLL == -9223372036854775807LL - 1"); + d2x::check_eq(maxULL, 18446744073709551615ULL, "maxULL == 18446744073709551615ULL"); // 2. Large integer application - representing world population int currentPopulation = 7800000000; - d2x_assert_eq(currentPopulation, 7800000000ULL); - - D2X_WAIT + d2x::check_eq(currentPopulation, 7800000000ULL, "currentPopulation == 7800000000ULL"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/14-type-alias-0.cpp b/src/en/cpp11/tests/14-type-alias/0.cpp similarity index 72% rename from dslings/en/cpp11/14-type-alias-0.cpp rename to src/en/cpp11/tests/14-type-alias/0.cpp index a011fb4..352b6b8 100644 --- a/dslings/en/cpp11/14-type-alias-0.cpp +++ b/src/en/cpp11/tests/14-type-alias/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/en/cpp11/14-type-alias-0.cpp +// file: src/en/cpp11/tests/14-type-alias/0.cpp // // Exercise: cpp11 | 14 - type alias | Basic Type Aliases // @@ -17,9 +17,9 @@ // d2x checker type-alias // -#include +import std; +import d2x; -#include int main() { @@ -27,24 +27,23 @@ int main() { D2X_YOUR_ANSWER Integer = int; D2X_YOUR_ANSWER = int; - bool ok = std::is_same::value; d2x_assert(ok); - ok = std::is_same::value; d2x_assert(ok); + bool ok = std::is_same::value; d2x::check(ok, "ok"); + ok = std::is_same::value; d2x::check(ok, "ok"); // 2. Using type aliases Integer a = 42; Real b = 3.14; // 3. Verifying type aliases - d2x_assert_eq(a, 42); - d2x_assert_eq(b, 3.14); + d2x::check_eq(a, 42, "a == 42"); + d2x::check_eq(b, 3.14, "b == 3.14"); // 4. Type aliases are essentially the same int c = 100; Integer d = c; // Can assign because they are essentially both int - d2x_assert_eq(c, d); - - D2X_WAIT + d2x::check_eq(c, d, "c == d"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/14-type-alias-1.cpp b/src/en/cpp11/tests/14-type-alias/1.cpp similarity index 78% rename from dslings/en/cpp11/14-type-alias-1.cpp rename to src/en/cpp11/tests/14-type-alias/1.cpp index 9578d00..4528ddf 100644 --- a/dslings/en/cpp11/14-type-alias-1.cpp +++ b/src/en/cpp11/tests/14-type-alias/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/en/cpp11/14-type-alias-1.cpp +// file: src/en/cpp11/tests/14-type-alias/1.cpp // // Exercise: cpp11 | 14 - type alias | Complex Types and Function Pointer Aliases // @@ -17,10 +17,9 @@ // d2x checker type-alias // -#include +import std; +import d2x; -#include -#include static int func_called = 0; @@ -37,7 +36,7 @@ int main() { FuncPtr func = example_func; func(1, 2); - d2x_assert_eq(func_called, 3); + d2x::check_eq(func_called, 3, "func_called == 3"); // 2. Container type alias // Use using to define an alias for vector @@ -54,11 +53,10 @@ int main() { Container::ValueType value = 100; // 4. Verifying type aliases - d2x_assert(strings[0] == "hello"); - d2x_assert(strings[1] == "world"); - d2x_assert_eq(value, 100); - - D2X_WAIT + d2x::check(strings[0] == "hello", "strings[0] == \"hello\""); + d2x::check(strings[1] == "world", "strings[1] == \"world\""); + d2x::check_eq(value, 100, "value == 100"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/14-type-alias-2.cpp b/src/en/cpp11/tests/14-type-alias/2.cpp similarity index 70% rename from dslings/en/cpp11/14-type-alias-2.cpp rename to src/en/cpp11/tests/14-type-alias/2.cpp index 4226637..4857785 100644 --- a/dslings/en/cpp11/14-type-alias-2.cpp +++ b/src/en/cpp11/tests/14-type-alias/2.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/en/cpp11/14-type-alias-2.cpp +// file: src/en/cpp11/tests/14-type-alias/2.cpp // // Exercise: cpp11 | 14 - type alias | Alias Templates Basics // @@ -17,11 +17,9 @@ // d2x checker type-alias // -#include +import std; +import d2x; -#include -#include -#include // 1. Basic alias template template @@ -41,15 +39,14 @@ int main() { Vec3 v3 = {1.0f, 2.0f, 3.0f}; Heap minHeap; - d2x_assert_eq(numbers[0], 1); - d2x_assert_eq(numbers[1], 2); - d2x_assert_eq(numbers[2], 3); + d2x::check_eq(numbers[0], 1, "numbers[0] == 1"); + d2x::check_eq(numbers[1], 2, "numbers[1] == 2"); + d2x::check_eq(numbers[2], 3, "numbers[2] == 3"); - d2x_assert_eq(v3[0], 1.0f); - d2x_assert_eq(v3[1], 2.0f); - d2x_assert_eq(v3[2], 3.0f); - - D2X_WAIT + d2x::check_eq(v3[0], 1.0f, "v3[0] == 1.0f"); + d2x::check_eq(v3[1], 2.0f, "v3[1] == 2.0f"); + d2x::check_eq(v3[2], 3.0f, "v3[2] == 3.0f"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/14-type-alias-3.cpp b/src/en/cpp11/tests/14-type-alias/3.cpp similarity index 82% rename from dslings/en/cpp11/14-type-alias-3.cpp rename to src/en/cpp11/tests/14-type-alias/3.cpp index 1d208ad..f35abb3 100644 --- a/dslings/en/cpp11/14-type-alias-3.cpp +++ b/src/en/cpp11/tests/14-type-alias/3.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/en/cpp11/14-type-alias-3.cpp +// file: src/en/cpp11/tests/14-type-alias/3.cpp // // Exercise: cpp11 | 14 - type alias | Standard Library Style Alias Templates // @@ -17,8 +17,8 @@ // d2x checker type-alias // -#include -#include +import std; +import d2x; int main() { @@ -30,10 +30,9 @@ int main() { bool ok = std::is_same, int*>::value; - d2x_assert(ok); - d2x_assert_eq(*ptr, 20); - - D2X_WAIT + d2x::check(ok, "ok"); + d2x::check_eq(*ptr, 20, "*ptr == 20"); + d2x::wait(); return 0; } \ No newline at end of file diff --git a/dslings/en/cpp11/15-variadic-templates-0.cpp b/src/en/cpp11/tests/15-variadic-templates/0.cpp similarity index 87% rename from dslings/en/cpp11/15-variadic-templates-0.cpp rename to src/en/cpp11/tests/15-variadic-templates/0.cpp index 25a8339..fe85706 100644 --- a/dslings/en/cpp11/15-variadic-templates-0.cpp +++ b/src/en/cpp11/tests/15-variadic-templates/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/15-variadic-templates-0.cpp +// file: src/en/cpp11/tests/15-variadic-templates/0.cpp // // Exercise: cpp11 | 15 - variadic templates | Variadic templates basics // @@ -20,8 +20,8 @@ // d2x checker variadic-templates // -#include -#include +import std; +import d2x; std::stringstream ss; @@ -41,9 +41,8 @@ int main() { print(1, "hello", 3.14); std::string result = ss.str(); - d2x_assert(result == "1 hello 3.14 "); - - D2X_WAIT + d2x::check(result == "1 hello 3.14 ", "result == \"1 hello 3.14 \""); + d2x::wait(); return 0; } diff --git a/dslings/en/cpp11/15-variadic-templates-1.cpp b/src/en/cpp11/tests/15-variadic-templates/1.cpp similarity index 77% rename from dslings/en/cpp11/15-variadic-templates-1.cpp rename to src/en/cpp11/tests/15-variadic-templates/1.cpp index 1eaa173..86c6819 100644 --- a/dslings/en/cpp11/15-variadic-templates-1.cpp +++ b/src/en/cpp11/tests/15-variadic-templates/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/cpp11/15-variadic-templates-1.cpp +// file: src/en/cpp11/tests/15-variadic-templates/1.cpp // // Exercise: cpp11 | 15 - variadic templates | Variadic template sum // @@ -13,7 +13,8 @@ // - https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/15-variadic-templates.md // -#include +import std; +import d2x; D2X_YOUR_ANSWER @@ -24,17 +25,16 @@ T sum(T first, D2X_YOUR_ANSWER) { int main() { int res1 = sum(1, 2, 3, 4, 5); - d2x_assert_eq(res1, 15); + d2x::check_eq(res1, 15, "res1 == 15"); double res2 = sum(1.5, 2.5, 3.0); - d2x_assert(res2 == 7.0); + d2x::check(res2 == 7.0, "res2 == 7.0"); // Mixed types // Note: the return type is determined by the first argument T int res3 = sum(10, 20.5); - d2x_assert_eq(res3, 30); - - D2X_WAIT + d2x::check_eq(res3, 30, "res3 == 30"); + d2x::wait(); return 0; } diff --git a/dslings/en/cpp11/16-generalized-unions-0.cpp b/src/en/cpp11/tests/16-generalized-unions/0.cpp similarity index 85% rename from dslings/en/cpp11/16-generalized-unions-0.cpp rename to src/en/cpp11/tests/16-generalized-unions/0.cpp index 3c1db5c..59dced2 100644 --- a/dslings/en/cpp11/16-generalized-unions-0.cpp +++ b/src/en/cpp11/tests/16-generalized-unions/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/en/cpp11/16-generalized-unions-0.cpp +// file: src/en/cpp11/tests/16-generalized-unions/0.cpp // // Exercise: cpp11 | 16 - generalized unions | generalized (non-trivial) unions // @@ -18,7 +18,8 @@ // d2x checker generalized-unions // -#include +import std; +import d2x; union M @@ -34,7 +35,7 @@ int main() { M u1; //Initialize union members - d2x_assert(u1.a1 == 42); + d2x::check(u1.a1 == 42, "u1.a1 == 42"); u1.a2 = 21; double val = 3.14; @@ -42,7 +43,6 @@ int main() { u1.c = 'x'; - D2X_WAIT - + d2x::wait(); return 0; } diff --git a/dslings/en/cpp11/16-generalized-unions-1.cpp b/src/en/cpp11/tests/16-generalized-unions/1.cpp similarity index 86% rename from dslings/en/cpp11/16-generalized-unions-1.cpp rename to src/en/cpp11/tests/16-generalized-unions/1.cpp index 8a18f76..d0b4be2 100644 --- a/dslings/en/cpp11/16-generalized-unions-1.cpp +++ b/src/en/cpp11/tests/16-generalized-unions/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/en/cpp11/16-generalized-unions-1.cpp +// file: src/en/cpp11/tests/16-generalized-unions/1.cpp // // Exercise: cpp11 | 16 - generalized unions | generalized (non-trivial) unions // @@ -18,8 +18,8 @@ // d2x checker generalized-unions // -#include -#include +import std; +import d2x; union M { @@ -43,12 +43,11 @@ int main() { u1.a2 = {1, D2X_YOUR_ANSWER, 3}; // 2. use assert to verify the contents - d2x_assert_eq(u1.a2[1], 42); + d2x::check_eq(u1.a2[1], 42, "u1.a2[1] == 42"); // 3. Manually call the destructor u1.a2.~vector(); - D2X_WAIT - + d2x::wait(); return 0; } diff --git a/dslings/en/cpp11/16-generalized-unions-2.cpp b/src/en/cpp11/tests/16-generalized-unions/2.cpp similarity index 81% rename from dslings/en/cpp11/16-generalized-unions-2.cpp rename to src/en/cpp11/tests/16-generalized-unions/2.cpp index 5cd28dc..dc7339d 100644 --- a/dslings/en/cpp11/16-generalized-unions-2.cpp +++ b/src/en/cpp11/tests/16-generalized-unions/2.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/en/cpp11/16-generalized-unions-2.cpp +// file: src/en/cpp11/tests/16-generalized-unions/2.cpp // // Exercise: cpp11 | 16 - generalized unions | tagged discriminated union // @@ -20,9 +20,8 @@ // d2x checker generalized-unions // -#include -#include -#include +import std; +import d2x; // Tag type — marks which member of the union is active enum class Tag { @@ -77,29 +76,28 @@ int main() { // 1. Construct an int value and verify Value v1(42); - d2x_assert(v1.tag == Tag::INTEGER); - d2x_assert_eq(v1.as_int(), 42); + d2x::check(v1.tag == Tag::INTEGER, "v1.tag == Tag::INTEGER"); + d2x::check_eq(v1.as_int(), 42, "v1.as_int() == 42"); // 2. Construct a string value and verify Value v2(std::string("hello")); - d2x_assert(v2.tag == Tag::STRING); - d2x_assert(v2.as_string() == "hello"); + d2x::check(v2.tag == Tag::STRING, "v2.tag == Tag::STRING"); + d2x::check(v2.as_string() == "hello", "v2.as_string() == \"hello\""); // 3. Switch from string to int { Value v3(std::string("world")); - d2x_assert(v3.as_string() == "world"); + d2x::check(v3.as_string() == "world", "v3.as_string() == \"world\""); // Manually destroy the string member, then switch to int v3.data.s.~basic_string(); v3.tag = Tag::INTEGER; v3.data.i = 100; - d2x_assert_eq(v3.as_int(), D2X_YOUR_ANSWER); + d2x::check_eq(v3.as_int(), D2X_YOUR_ANSWER, "v3.as_int() == D2X_YOUR_ANSWER"); // When v3 goes out of scope, ~Value() sees tag == INTEGER, skips string destruction } - D2X_WAIT - + d2x::wait(); return 0; } diff --git a/dslings/en/cpp11/17-pod-type-0.cpp b/src/en/cpp11/tests/17-pod-type/0.cpp similarity index 87% rename from dslings/en/cpp11/17-pod-type-0.cpp rename to src/en/cpp11/tests/17-pod-type/0.cpp index 970992d..a1dfa13 100644 --- a/dslings/en/cpp11/17-pod-type-0.cpp +++ b/src/en/cpp11/tests/17-pod-type/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/en/cpp11/17-pod-type-0.cpp +// file: src/en/cpp11/tests/17-pod-type/0.cpp // // Exercise: cpp11 | 17 - POD Type | Basic type properties // @@ -18,9 +18,9 @@ // // d2x checker pod-type -#include +import std; +import d2x; -#include struct A { int x; @@ -53,21 +53,21 @@ int main() { // 3. Check if A is trivial / standard_layout type, write the result to ok bool ok = D2X_YOUR_ANSWER; - d2x_assert(ok); + d2x::check(ok, "ok"); // 4. Check if B is trivial / standard_layout type, write the result to ok ok = D2X_YOUR_ANSWER; - d2x_assert(ok); + d2x::check(ok, "ok"); // 5. Check if C is trivial type, write the result to ok ok = D2X_YOUR_ANSWER; - d2x_assert(ok); + d2x::check(ok, "ok"); // 6. Check if D is not standard_layout type, write the result to ok ok = D2X_YOUR_ANSWER; - d2x_assert(!ok); + d2x::check(!ok, "!ok"); - D2X_WAIT + d2x::wait(); } diff --git a/dslings/en/cpp11/17-pod-type-1.cpp b/src/en/cpp11/tests/17-pod-type/1.cpp similarity index 72% rename from dslings/en/cpp11/17-pod-type-1.cpp rename to src/en/cpp11/tests/17-pod-type/1.cpp index 074f27f..2f03b5a 100644 --- a/dslings/en/cpp11/17-pod-type-1.cpp +++ b/src/en/cpp11/tests/17-pod-type/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/en/cpp11/17-pod-type-1.cpp +// file: src/en/cpp11/tests/17-pod-type/1.cpp // // Exercise: cpp11 | 17 - POD Type | Byte-wise copying of a POD struct // @@ -18,10 +18,9 @@ // // d2x checker pod-type -#include +import std; +import d2x; -#include -#include struct Packet { std::uint32_t len; @@ -40,12 +39,11 @@ int main() { // TODO: use std::memcpy to copy the contents of p1 into p2. D2X_YOUR_ANSWER; - d2x_assert_eq(p2.len, 42u); - d2x_assert_eq(p2.type, static_cast(1)); - d2x_assert_eq(p2.flags, static_cast(0xFF)); - - D2X_WAIT + d2x::check_eq(p2.len, 42u, "p2.len == 42u"); + d2x::check_eq(p2.type, static_cast(1), "p2.type == static_cast(1)"); + d2x::check_eq(p2.flags, static_cast(0xFF), "p2.flags == static_cast(0xFF)"); + d2x::wait(); return 0; } diff --git a/dslings/en/cpp11/17-pod-type-2.cpp b/src/en/cpp11/tests/17-pod-type/2.cpp similarity index 78% rename from dslings/en/cpp11/17-pod-type-2.cpp rename to src/en/cpp11/tests/17-pod-type/2.cpp index ce31790..7c39ace 100644 --- a/dslings/en/cpp11/17-pod-type-2.cpp +++ b/src/en/cpp11/tests/17-pod-type/2.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/en/cpp11/17-pod-type-2.cpp +// file: src/en/cpp11/tests/17-pod-type/2.cpp // // Exercise: cpp11 | 17 - POD Type | Adapting a C++ message to a C POD header // @@ -18,10 +18,9 @@ // // d2x checker pod-type -#include +import std; +import d2x; -#include -#include // C-style message header, POD-only, used for cross-language / cross-module transfer. struct MessageHeader { @@ -41,7 +40,7 @@ static MessageHeader g_last_header{}; extern "C" void c_send_header(const void* data, std::size_t size) { // In a real-world scenario, this might be a C library or system call. - d2x_assert_eq(size, sizeof(MessageHeader)); + d2x::check_eq(size, sizeof(MessageHeader), "size == sizeof(MessageHeader)"); const auto* header = static_cast(data); g_last_header = *header; } @@ -62,12 +61,11 @@ int main() { send_message_to_c(msg); // Verify that the C interface received the correct header contents. - d2x_assert_eq(g_last_header.type, msg.type); - d2x_assert_eq(g_last_header.len, static_cast(msg.payload.size())); - d2x_assert_eq(g_last_header.flags, static_cast(0)); - - D2X_WAIT + d2x::check_eq(g_last_header.type, msg.type, "g_last_header.type == msg.type"); + d2x::check_eq(g_last_header.len, static_cast(msg.payload.size()), "g_last_header.len == static_cast(msg.payload.size())"); + d2x::check_eq(g_last_header.flags, static_cast(0), "g_last_header.flags == static_cast(0)"); + d2x::wait(); return 0; } diff --git a/src/en/cpp14/mcpp.toml b/src/en/cpp14/mcpp.toml new file mode 100644 index 0000000..6ef0957 --- /dev/null +++ b/src/en/cpp14/mcpp.toml @@ -0,0 +1,10 @@ +# cpp14 (en) 练习工程。练习 = tests/<章节>/<序号>.cpp,由 mcpp test 直接驱动: +# mcpp test -p src/en/cpp14 全部练习(进度表) +# mcpp test -p src/en/cpp14 <子串> 只跑匹配的练习 +[package] +name = "en-cpp14" +version = "0.1.0" +standard = "c++23" + +[dependencies] +d2x = { path = "../../../d2x" } diff --git a/dslings/en/cpp14/00-generic-lambdas-0.cpp b/src/en/cpp14/tests/00-generic-lambdas/0.cpp similarity index 57% rename from dslings/en/cpp14/00-generic-lambdas-0.cpp rename to src/en/cpp14/tests/00-generic-lambdas/0.cpp index 3d2c16e..d21832a 100644 --- a/dslings/en/cpp14/00-generic-lambdas-0.cpp +++ b/src/en/cpp14/tests/00-generic-lambdas/0.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/en/cpp14/00-generic-lambdas-0.cpp +// file: src/en/cpp14/tests/00-generic-lambdas/0.cpp // // Exercise: cpp14 | 00 - generic lambdas | basic generic lambda // @@ -20,8 +20,8 @@ // d2x checker generic-lambdas // -#include -#include +import std; +import d2x; int main() { @@ -30,28 +30,27 @@ int main() { return x; }; - d2x_assert_eq(identity(42), 42); - d2x_assert(identity(std::string("hello")) == "hello"); - d2x_assert_eq(identity(3.14), D2X_YOUR_ANSWER); + d2x::check_eq(identity(42), 42, "identity(42) == 42"); + d2x::check(identity(std::string("hello")) == "hello", "identity(std::string(\"hello\")) == \"hello\""); + d2x::check_eq(identity(3.14), D2X_YOUR_ANSWER, "identity(3.14) == D2X_YOUR_ANSWER"); // 1. Generic lambda as comparator auto greater = [](auto a, auto b) { return D2X_YOUR_ANSWER; }; - d2x_assert(greater(5, 3)); - d2x_assert(greater(2.5, 1.2)); - d2x_assert(greater(std::string("z"), std::string("a"))); + d2x::check(greater(5, 3), "greater(5, 3)"); + d2x::check(greater(2.5, 1.2), "greater(2.5, 1.2)"); + d2x::check(greater(std::string("z"), std::string("a")), "greater(std::string(\"z\"), std::string(\"a\"))"); // 2. Verify deduced types auto get_type_size = [](auto x) { return sizeof(D2X_YOUR_ANSWER); }; - d2x_assert_eq(get_type_size(42), sizeof(int)); - d2x_assert_eq(get_type_size('c'), sizeof(char)); - - D2X_WAIT + d2x::check_eq(get_type_size(42), sizeof(int), "get_type_size(42) == sizeof(int)"); + d2x::check_eq(get_type_size('c'), sizeof(char), "get_type_size('c') == sizeof(char)"); + d2x::wait(); return 0; } diff --git a/dslings/en/cpp14/00-generic-lambdas-1.cpp b/src/en/cpp14/tests/00-generic-lambdas/1.cpp similarity index 75% rename from dslings/en/cpp14/00-generic-lambdas-1.cpp rename to src/en/cpp14/tests/00-generic-lambdas/1.cpp index d23df54..5405b62 100644 --- a/dslings/en/cpp14/00-generic-lambdas-1.cpp +++ b/src/en/cpp14/tests/00-generic-lambdas/1.cpp @@ -1,6 +1,6 @@ // d2mcpp: https://github.com/mcpp-community/d2mcpp // license: Apache-2.0 -// file: dslings/en/cpp14/00-generic-lambdas-1.cpp +// file: src/en/cpp14/tests/00-generic-lambdas/1.cpp // // Exercise: cpp14 | 00 - generic lambdas | generic lambda with STL algorithms // @@ -20,9 +20,8 @@ // d2x checker generic-lambdas // -#include -#include -#include +import std; +import d2x; int main() { @@ -35,11 +34,11 @@ int main() { }; std::sort(v1.begin(), v1.end(), desc); - d2x_assert_eq(v1[0], 8); - d2x_assert_eq(v1[4], 1); + d2x::check_eq(v1[0], 8, "v1[0] == 8"); + d2x::check_eq(v1[4], 1, "v1[4] == 1"); std::sort(v2.begin(), v2.end(), desc); - d2x_assert_eq(v2[0], D2X_YOUR_ANSWER); + d2x::check_eq(v2[0], D2X_YOUR_ANSWER, "v2[0] == D2X_YOUR_ANSWER"); // 1. Generic lambda with capture — find_if int threshold = 3; @@ -48,10 +47,10 @@ int main() { }; auto it1 = std::find_if(v1.begin(), v1.end(), above); - d2x_assert(*it1 == D2X_YOUR_ANSWER); + d2x::check(*it1 == D2X_YOUR_ANSWER, "*it1 == D2X_YOUR_ANSWER"); auto it2 = std::find_if(v2.begin(), v2.end(), above); - d2x_assert(*it2 == 8.5); + d2x::check(*it2 == 8.5, "*it2 == 8.5"); // 2. Generic lambda returning lambda — factory function auto make_multiplier = [](auto factor) { @@ -59,10 +58,9 @@ int main() { }; auto times2 = make_multiplier(2); - d2x_assert_eq(times2(10), 20); - d2x_assert_eq(times2(0.5), 1.0); - - D2X_WAIT + d2x::check_eq(times2(10), 20, "times2(10) == 20"); + d2x::check_eq(times2(0.5), 1.0, "times2(0.5) == 1.0"); + d2x::wait(); return 0; } diff --git a/src/en/intro/mcpp.toml b/src/en/intro/mcpp.toml new file mode 100644 index 0000000..7353556 --- /dev/null +++ b/src/en/intro/mcpp.toml @@ -0,0 +1,10 @@ +# intro (en) 练习工程。练习 = tests/<章节>/<序号>.cpp,由 mcpp test 直接驱动: +# mcpp test -p src/en/intro 全部练习(进度表) +# mcpp test -p src/en/intro <子串> 只跑匹配的练习 +[package] +name = "en-intro" +version = "0.1.0" +standard = "c++23" + +[dependencies] +d2x = { path = "../../../d2x" } diff --git a/src/en/intro/tests/hello-mcpp.cpp b/src/en/intro/tests/hello-mcpp.cpp new file mode 100644 index 0000000..55aa1bb --- /dev/null +++ b/src/en/intro/tests/hello-mcpp.cpp @@ -0,0 +1,81 @@ +// mcpp-standard: https://github.com/Sunrisepeak/mcpp-standard +// license: Apache-2.0 +// file: src/en/intro/tests/hello-mcpp.cpp +// +// Exercise: Automated Code Practice Usage Tutorial +// +// Tips: +// This is an "exercises are tests" automated practice project. Two modes of use: +// +// d2x checker guided mode: auto-detects your edits, passing advances you +// mcpp test -p src/en/intro native mode: plain mcpp — the test report IS your progress +// +// Fix the code based on console error messages. There are only three conventions: +// +// - D2X_YOUR_ANSWER: the fill-in-the-blank placeholder — replace it with correct +// code. It is not a macro, just a name nobody defines, so the compiler error +// points exactly at the blank +// - d2x::check / d2x::check_eq: runtime checkpoints — fix the code so every +// check passes (do not delete the checkpoints) +// - d2x::wait(): the barrier between exercises — delete it once you have read +// the lesson to really finish it +// +// Docs: +// - https://github.com/Sunrisepeak/mcpp-standard/blob/main/book/src/chapter_1.md +// - book/src/chapter_1.md +// +// Auto-Checker command: +// +// d2x checker hello-mcpp +// + +import std; +import d2x; + +// You can observe "real-time" changes in the console when modifying code + +int main() { + + std::cout << "hello, mcpp!" << std:endl; // 0. Fix this compilation error + + int a = 1.1; // 1. Fix this runtime error, change int to double to pass the check + + d2x::check_eq(a, 1.1, "a == 1.1"); // 2. Runtime checkpoint, need to fix code to pass all checkpoints (cannot directly delete checkpoint code) + + D2X_YOUR_ANSWER b = a; // 3. Fix this compilation error, give b an appropriate type + + d2x::check_eq(b, 1, "b == 1"); // 4. Runtime checkpoint 2 + + d2x::wait(); // 5. Delete or comment out this line to proceed to the next exercise (project formal code practice) + + return 0; +} + +//// --- More detailed introduction | | | +// V V V +/* + +# [[ Console Output Interpretation ]] + +🌏Progress: [>----------] 0/52 -->> Shows current exercise progress + +[Exercise: hello-mcpp] -->> Current exercise name + +❌ Error: Compilation/Running failed for src/en/intro/tests/hello-mcpp.cpp -->> Shows detection status + + The code exist some error! + +---------Output--------- - Compile/run output information +❌ | a == 1.1 (1 == 1.1) --> src/en/intro/tests/hello-mcpp.cpp:46 -->> Error prompt and location (line 46) +🚧 | Delete the d2x::wait() to continue --> src/en/intro/tests/hello-mcpp.cpp:52 + + +AI-Tips-Config: https://xlings.d2learn.org/en/documents/d2x/intro.html -->> AI tips (requires configuring large model key, optional) + +---------E-Files--------- +src/en/intro/tests/hello-mcpp.cpp -->> Current file being checked +------------------------- + +Homepage: https://github.com/openxlings/xlings + +*/ diff --git a/src/intro/mcpp.toml b/src/intro/mcpp.toml new file mode 100644 index 0000000..3772c86 --- /dev/null +++ b/src/intro/mcpp.toml @@ -0,0 +1,10 @@ +# intro 练习工程。练习 = tests/<章节>/<序号>.cpp,由 mcpp test 直接驱动: +# mcpp test -p src/intro 全部练习(进度表) +# mcpp test -p src/intro <子串> 只跑匹配的练习 +[package] +name = "intro" +version = "0.1.0" +standard = "c++23" + +[dependencies] +d2x = { path = "../../d2x" } diff --git a/src/intro/tests/hello-mcpp.cpp b/src/intro/tests/hello-mcpp.cpp new file mode 100644 index 0000000..2bac4d5 --- /dev/null +++ b/src/intro/tests/hello-mcpp.cpp @@ -0,0 +1,76 @@ +// d2mcpp: https://github.com/mcpp-community/d2mcpp +// license: Apache-2.0 +// file: src/intro/tests/hello-mcpp.cpp +// +// Exercise/练习: 自动化代码练习使用教学 +// +// Tips/提示: +// 这是一个「练习即测试」的自动化代码练习项目。两种使用方式任选: +// +// d2x checker 引导模式: 自动检测,通过后进入下一题 +// mcpp test -p src/intro 原生模式: 直接使用 mcpp 运行, 测试报告即学习进度 +// +// 你需要根据控制台的报错和提示信息修改代码。约定只有三个: +// +// - D2X_YOUR_ANSWER: 填空占位符 —— 用正确的代码替换它。它不是宏, +// 只是一个没人定义的名字, 所以编译器会指着它报错, 那就是要填的地方 +// - d2x::check / d2x::check_eq: 运行时检查点, 修复代码让所有检查通过 +// (不能直接删除检查点) +// - d2x::wait(): 练习之间的路障 —— 读完这一课, 删掉它才算真正完成 +// +// Docs/文档: +// - https://github.com/mcpp-community/d2mcpp/blob/main/book/src/chapter_1.md +// - book/src/chapter_1.md +// +// Auto-Checker/自动检测命令: +// +// d2x checker hello-mcpp +// + +import std; +import d2x; + +// 修改代码时可以观察到控制台"实时"的变化 + +int main() { + + std::cout << "hello, mcpp!" << std:endl; // 0.修复这个编译错误 + + int a = 1.1; // 1.修复这个运行时错误, 修改int为double, 通过检查 + + d2x::check_eq(a, 1.1, "a == 1.1"); // 2.运行时检查点, 需要修复代码通过所有检查点(不能直接删除检查点代码) + + int b = a; // 3.修复这个编译错误, 给b一个合适的类型 + + d2x::check_eq(b, 1, "b == 1"); // 4.运行时检查点2 + + d2x::wait(); // 5.删除或注释掉这一行, 进入下一个练习(项目正式代码练习) + + return 0; +} + +//// --- 更多详细介绍 | | | +// V V V +/* + +# [[ 控制台输出解读 ]] + +🌏Progress: [>----------] 0/52 -->> 显示当前的练习进度 + +[Exercise: hello-mcpp] -->> 当前的练习名 + +❌ Error: Compilation/Running failed for src/intro/tests/hello-mcpp.cpp -->> 显示检测状态 + +---------Output--------- - 编译/运行输出信息 +❌ | a == 1.1 (1 == 1.1) --> src/intro/tests/hello-mcpp.cpp:41 -->> 错误提示及位置(41行) +🚧 | Delete the d2x::wait() to continue --> src/intro/tests/hello-mcpp.cpp:47 + +AI-Tips-Config: https://xlings.d2learn.org/documents/d2x/intro.html -->> AI提示(需要配置大模型的key, 可不使用) + +---------E-Files--------- +src/intro/tests/hello-mcpp.cpp -->> 当前检测的文件 +------------------------- + +Homepage: https://github.com/openxlings/xlings + +*/ diff --git a/xmake.lua b/xmake.lua deleted file mode 100644 index e37aca0..0000000 --- a/xmake.lua +++ /dev/null @@ -1,6 +0,0 @@ -add_plugindirs("d2x/buildtools") - -add_includedirs(".") - -includes("dslings/xmake.lua") ---includes("solutions/xmake.lua") \ No newline at end of file