From bfaed2837c594b4f604836238490c63a51a4a77c Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Tue, 9 Jun 2026 15:17:22 +0800 Subject: [PATCH 1/3] video(cpp11/00): add manim animation for auto/decltype Manim Community v0.18.1 scene mirroring the existing videos/cpp11/* framework (MovingCameraScene + d2x mcpp_video_start/end, DHighlight, create_code_helper). Six scenes following the chapter: declaration, expression deduction, complex types (iterator), trailing-return + decltype, const/reference stripping, and the decltype parentheses pitfall. Run: uv run --with "manim==0.18.1" manim -pql videos/cpp11/00-auto-and-decltype.py --- videos/cpp11/00-auto-and-decltype.py | 174 +++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 videos/cpp11/00-auto-and-decltype.py diff --git a/videos/cpp11/00-auto-and-decltype.py b/videos/cpp11/00-auto-and-decltype.py new file mode 100644 index 0000000..c28bffa --- /dev/null +++ b/videos/cpp11/00-auto-and-decltype.py @@ -0,0 +1,174 @@ +import sys, os +from manim import * + +""" +Manim Community v0.18.1 + +# 用 uv 运行(无需预装 manim): +uv run --with "manim==0.18.1" manim -pql videos/cpp11/00-auto-and-decltype.py +uv run --with "manim==0.18.1" manim -pqh videos/cpp11/00-auto-and-decltype.py +""" + +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) + +from d2x import * + +class AutoAndDecltype(MovingCameraScene): + def construct(self): + + title, logo = mcpp_video_start(self, "{ auto / decltype }") + + self.wait(0.5) + + self.play(Transform(title, Text("{ 类型自动推导 }", t2c={'类型自动推导': BLUE}))) + + self.wait(0.5) + + # 场景1: 声明定义 —— auto 从初始值推导, decltype 取声明类型 + self.play(Transform(title, Text("{ 1 - 声明定义 }", t2c={'声明定义': BLUE}))) + + self.wait(0.5) + + code1 = self.create_code_helper("""int b = 2; +auto b1 = b; // b1: int +decltype(b) b2 = b; // b2: int""") + + self.play(ReplacementTransform(title, code1)) + + self.wait(0.5) + + self.play(DHighlight(code1.code[1])) # auto: 从初始值推导 + + self.wait(0.5) + + self.play(DHighlight(code1.code[2])) # decltype: 取声明类型 + + self.wait(0.5) + + # 场景2: 表达式类型推导 —— 保留计算精度 + title = Text("{ 2 - 表达式类型推导 }", t2c={'表达式': BLUE}) + self.play(ReplacementTransform(code1, title)) + + self.wait(0.5) + + code2 = self.create_code_helper("""int a = 1; +auto x = a + 2 + 1.1; // double +decltype(a + 2 + 1.1) y = x; // double""") + + self.play(ReplacementTransform(title, code2)) + + self.wait(0.5) + + self.play(DHighlight(code2.code[1], color=GREEN)) + self.play(DHighlight(code2.code[2], color=GREEN)) + + self.wait(0.5) + + # 场景3: 复杂类型推导 —— auto 驯服冗长的迭代器类型(STL 真实场景) + title = Text("{ 3 - 复杂类型推导 }", t2c={'复杂类型': BLUE}) + self.play(ReplacementTransform(code2, title)) + + self.wait(0.5) + + code3a = self.create_code_helper("""std::vector v = {1, 2, 3}; +std::vector::iterator it = v.begin();""") + + self.play(ReplacementTransform(title, code3a)) + + self.wait(0.5) + + self.play(DHighlight(code3a.code[1], color=PURE_RED)) # 又长又难写 + + self.wait(0.5) + + code3b = self.create_code_helper("""std::vector v = {1, 2, 3}; +auto it = v.begin();""") + + self.play(ReplacementTransform(code3a, code3b)) + + self.wait(0.5) + + self.play(DHighlight(code3b.code[1], color=GREEN)) # auto 一步到位 + + self.wait(0.5) + + # 场景4: 函数返回值类型推导 —— 后置返回 + decltype + title = Text("{ 4 - 函数返回值推导 }", t2c={'函数返回值': BLUE}) + self.play(ReplacementTransform(code3b, title)) + + self.wait(0.5) + + code4 = self.create_code_helper("""template +auto add(T1 a, T2 b) -> decltype(a + b) { + return a + b; +}""") + + self.play(ReplacementTransform(title, code4)) + + self.wait(0.5) + + self.play(DHighlight(code4.code[1])) # auto ... -> decltype(a + b) + + self.wait(0.5) + + # 场景5: 注意事项 —— auto 剥离 const / 引用, 想保留要显式写 + title = Text("{ 5 - const / 引用剥离 }", t2c={'const / 引用': PURE_RED}) + self.play(ReplacementTransform(code4, title)) + + self.wait(0.5) + + code5 = self.create_code_helper("""const int ci = 1; +auto a = ci; // int (const lost!) +const auto& r = ci; // const int& +decltype(ci) d = ci; // const int""") + + self.play(ReplacementTransform(title, code5)) + + self.wait(0.5) + + self.play(DHighlight(code5.code[1], color=PURE_RED)) # 顶层 const 被剥离 + + self.wait(0.5) + + self.play(DHighlight(code5.code[2], color=GREEN)) # const auto& 保留 + self.play(DHighlight(code5.code[3], color=GREEN)) # decltype 精确保留 + + self.wait(0.5) + + # 场景6: 注意事项 —— decltype 的括号陷阱 + title = Text("{ 6 - decltype 括号陷阱 }", t2c={'括号陷阱': PURE_RED}) + self.play(ReplacementTransform(code5, title)) + + self.wait(0.5) + + code6 = self.create_code_helper("""int a = 1; +decltype(a) b; // int +decltype((a)) c; // int&""") + + self.play(ReplacementTransform(title, code6)) + + self.wait(0.5) + + self.play(DHighlight(code6.code[1])) # decltype(a): 声明类型 int + + self.wait(0.5) + + select_box = SurroundingRectangle(code6.code[2], color=PURE_RED, buff=0.1) + self.play(Create(select_box)) + self.play(DHighlight(code6.code[2], color=PURE_RED)) # decltype((a)): 左值表达式 -> int& + + self.wait(0.5) + + mcpp_video_end(self, logo, VGroup(code6, select_box)) + + @staticmethod + def create_code_helper(code: str): + return Code( + code=code, + background="", + language="cpp", + ) + +if __name__ == "__main__": + scene = AutoAndDecltype() + scene.render() From 127d26d10ba71fbaaf911b402d293435b67727df Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 14 Jun 2026 09:54:01 +0800 Subject: [PATCH 2/3] docs(cpp11/00): sync bilingual docs + add animation video link - Sync en doc to zh: iterator example (v.insert) and const/reference stripping example now match the zh version's code - Add Bilibili animation link (BV1EzJs6HEf7) alongside the existing explanation video in both book docs and videos/README.md - Add render.sh launcher and refine the manim animation script --- book/en/src/cpp11/00-auto-and-decltype.md | 75 ++-- book/src/cpp11/00-auto-and-decltype.md | 75 ++-- videos/README.md | 36 +- videos/cpp11/00-auto-and-decltype.py | 436 ++++++++++++++++++---- videos/d2x/video.py | 2 +- videos/render.sh | 42 +++ 6 files changed, 530 insertions(+), 136 deletions(-) create mode 100755 videos/render.sh diff --git a/book/en/src/cpp11/00-auto-and-decltype.md b/book/en/src/cpp11/00-auto-and-decltype.md index eebb1f4..343a3eb 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/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/BV1xkdYYUEyH) / [Animation](https://www.bilibili.com/video/BV1EzJs6HEf7) | [Practice Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/00-auto-and-decltype-0.cpp) | | **Why were they introduced?** @@ -61,10 +61,14 @@ decltype(2 + 'a') c2 = 2 + 'a'; ```cpp std::vector v = {1, 2, 3}; +// std::vector::iterator it = v.begin(); auto it = v.begin(); // Automatically deduce iterator type // decltype(v.begin()) it = v.begin(); for (; it != v.end(); ++it) { - std::cout << *it << " "; + if (*it == 2) { + v.insert(it, 0); + break; + } } ``` @@ -137,41 +141,42 @@ int main() { ## II. Real-World Case - auto/decltype in the STL -> The examples above illustrate syntax; the real value of auto/decltype shows up most directly in the standard library's own implementation. Below we use the in-repo [MSVC STL](https://github.com/mcpp-community/d2mcpp/tree/main/msvc-stl) as the source ([`msvc-stl/stl/inc/xutility`](https://github.com/mcpp-community/d2mcpp/blob/main/msvc-stl/stl/inc/xutility#L2200-L2235)); `_EXPORT_STD` / `_NODISCARD` / `_CONSTEXPR17` / `_STD` are internal library macros — ignore them when reading. +> The examples above illustrate syntax; the practical value of auto/decltype is demonstrated most directly in the standard library's own implementation. The following picks two common pieces of code from the in-repo [MSVC STL](https://github.com/mcpp-community/d2mcpp/tree/main/msvc-stl) to demonstrate `auto` and `decltype` respectively; `_STD` and the like are internal library macros and qualifiers — focus on the `auto` / `decltype` when reading. -### Trailing return type + decltype: std::begin / std::end +### auto deduces iterator and element types: traversing a container -`std::begin` / `std::end` (added in C++11) must adapt to any container; their return type depends entirely on `_Cont.begin()` and cannot be written ahead of time, so they "borrow" it via `auto ... -> decltype(...)` +Traversing a container is the most common scenario for `auto`. Below is a traversal from path normalization in ``: `auto _Pos` deduces the iterator type, and `const auto _Elem` deduces the element type obtained by dereferencing — the very same form as `auto it = v.begin()` from "Complex type deduction - iterators" in `## I`. ```cpp -// MSVC STL · msvc-stl/stl/inc/xutility (abridged) -_EXPORT_STD template -_NODISCARD _CONSTEXPR17 auto begin(_Container& _Cont) noexcept(noexcept(_Cont.begin())) -> decltype(_Cont.begin()) { - return _Cont.begin(); -} - -_EXPORT_STD template -_NODISCARD _CONSTEXPR17 auto end(_Container& _Cont) noexcept(noexcept(_Cont.end())) -> decltype(_Cont.end()) { - return _Cont.end(); -} +// MSVC STL · msvc-stl/stl/inc/filesystem (abridged, original indentation kept) + auto _New_end = _Vec.begin(); + for (auto _Pos = _Vec.begin(); _Pos != _Vec.end();) { + const auto _Elem = *_Pos++; + // ...(decide whether to write _Elem back to _New_end; omitted) + } ``` -This is exactly the trailing-return form from the "Function Return Type Deduction" section, living inside the standard library itself: `auto` as the placeholder + `decltype(_Cont.begin())` precisely deducing the differing iterator types of `vector`, `list`, and so on. +`_Vec` is the container of path components; both its iterator type and its element type are left to `auto`, with no need to spell out the concrete types. -### Reusing another function's return type with decltype: std::cbegin / std::cend +### decltype takes the type of a variable: the binary search in std::lower_bound -Going further, `std::cbegin` simply reuses `begin`'s return type via `decltype(_STD begin(_Cont))` — it doesn't care what that type is, only that it "matches what begin returns" +The most direct use of `decltype` is "take the type of a variable or expression". In the standard library's binary search `std::lower_bound`, `auto` first deduces the range length `_Count`, then `decltype(_Count)` denotes "the same type as `_Count`" to convert `_Count / 2` back to that type: ```cpp -// MSVC STL · msvc-stl/stl/inc/xutility (abridged) -_EXPORT_STD template -_NODISCARD constexpr auto cbegin(const _Container& _Cont) noexcept(noexcept(_STD begin(_Cont))) - -> decltype(_STD begin(_Cont)) { - return _STD begin(_Cont); -} +// MSVC STL · msvc-stl/stl/inc/xutility (abridged) —— std::lower_bound + auto _UFirst = _STD _Get_unwrapped(_First); + auto _Count = _STD distance(_UFirst, _STD _Get_unwrapped(_Last)); + + while (0 < _Count) { // divide and conquer, find half that contains answer + const auto _Count2 = static_cast(_Count / 2); + const auto _UMid = _STD next(_UFirst, _Count2); + // ...(compare at _UMid, narrow the range; omitted) + } ``` -> Takeaway: when a type "is decided by template parameters and simply cannot be written by hand", the standard library reaches for exactly the auto + decltype toolkit taught in this chapter — one of the core motivations for introducing them in C++11. +This is the same use as `decltype(b) b2` from "Declaration and definition" in `## I`: `decltype(_Count)` is simply "the type of `_Count`". `auto` deduces the type, and `decltype` reuses that same type elsewhere. + +> Takeaway: traversing a container, reusing the type of some variable — these everyday forms are, inside the standard library, exactly the auto + decltype toolkit taught in this chapter. This is one of the core motivations for introducing them in C++11. ## III. Important Notes @@ -180,17 +185,21 @@ _NODISCARD constexpr auto cbegin(const _Container& _Cont) noexcept(noexcept(_STD > auto deduction **strips top-level const and references**; to keep them you must write `const auto&` / `auto&` explicitly, whereas decltype preserves the declared type exactly ```cpp -const int ci = 1; -int n = 2; -int& ri = n; +int a = 1; +int &b = a; +const int c = 1; +const int &d = c; -auto a = ci; // int — top-level const stripped -auto b = ri; // int — reference stripped (b is an independent copy of n) +auto a1 = a; // int +auto b1 = b; // int +auto c1 = c; // int +auto d1 = d; // int -const auto& r1 = ci; // const int& — preserved via const auto& -auto&& r2 = ci; // const int& — forwarding reference keeps it +const auto c2 = c; // const int +const auto &d2 = d; // const int & -decltype(ci) d = ci; // const int — decltype preserves exactly +decltype(c) c3 = c; // const int +decltype(d) d3 = d; // const int & ``` This is also why `auto a = obj.a;` in "Class/Struct Member Type Deduction" yields `int` rather than `const int` — auto stripped the top-level const. diff --git a/book/src/cpp11/00-auto-and-decltype.md b/book/src/cpp11/00-auto-and-decltype.md index 7384c6f..293e330 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/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/BV1xkdYYUEyH) / [动画演示](https://www.bilibili.com/video/BV1EzJs6HEf7) | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp11/00-auto-and-decltype-0.cpp) | | **为什么引入?** @@ -61,10 +61,14 @@ decltype(2 + 'a') c2 = 2 + 'a'; ```cpp std::vector v = {1, 2, 3}; +// std::vector::iterator it = v.begin(); auto it = v.begin(); // 自动推导it类型 // decltype(v.begin()) it = v.begin(); for (; it != v.end(); ++it) { - std::cout << *it << " "; + if (*it == 2) { + v.insert(it, 0); + break; + } } ``` @@ -137,41 +141,42 @@ int main() { ## 二、真实案例 - STL 中的 auto/decltype -> 前面的例子是为了讲语法, 而 auto/decltype 真正的价值, 在标准库自己的实现里体现得最直接。下面以仓库内置的 [MSVC STL](https://github.com/mcpp-community/d2mcpp/tree/main/msvc-stl) 为例 (源码: [`msvc-stl/stl/inc/xutility`](https://github.com/mcpp-community/d2mcpp/blob/main/msvc-stl/stl/inc/xutility#L2200-L2235)); `_EXPORT_STD` / `_NODISCARD` / `_CONSTEXPR17` / `_STD` 是库内部宏, 阅读时可忽略 +> 前述示例用于讲解语法, 而 auto/decltype 的实际价值, 在标准库自身的实现中体现得最为直接。下面从仓库内置的 [MSVC STL](https://github.com/mcpp-community/d2mcpp/tree/main/msvc-stl) 中选取两段常见代码, 分别演示 `auto` 与 `decltype`; `_STD` 等是库内部的宏与限定写法, 阅读时关注 `auto` / `decltype` 即可 -### 后置返回类型 + decltype:std::begin / std::end +### auto 推导迭代器与元素类型:遍历容器 -`std::begin` / `std::end` (C++11 新增) 要适配任意容器, 返回类型完全取决于 `_Cont.begin()`, 没法提前写死, 于是直接用 `auto ... -> decltype(...)` 把返回类型"借"过来 +遍历容器是 `auto` 最常见的场景。下面是 `` 规范化路径时的一段遍历:`auto _Pos` 推导出迭代器类型, `const auto _Elem` 推导出解引用后的元素类型 —— 与 `## 一`「复杂类型推导 - 迭代器」里的 `auto it = v.begin()` 完全是同一种写法 ```cpp -// MSVC STL · msvc-stl/stl/inc/xutility (有删节) -_EXPORT_STD template -_NODISCARD _CONSTEXPR17 auto begin(_Container& _Cont) noexcept(noexcept(_Cont.begin())) -> decltype(_Cont.begin()) { - return _Cont.begin(); -} - -_EXPORT_STD template -_NODISCARD _CONSTEXPR17 auto end(_Container& _Cont) noexcept(noexcept(_Cont.end())) -> decltype(_Cont.end()) { - return _Cont.end(); -} +// MSVC STL · msvc-stl/stl/inc/filesystem (有删节, 缩进保留源码层级) + auto _New_end = _Vec.begin(); + for (auto _Pos = _Vec.begin(); _Pos != _Vec.end();) { + const auto _Elem = *_Pos++; + // ...(根据 _Elem 决定是否写回 _New_end, 略) + } ``` -这正是本章「函数返回值类型推导」一节讲的后置返回写法在标准库里的真身: `auto` 占位 + `decltype(_Cont.begin())` 精确推导出 `vector::iterator`、`list::iterator` 等各不相同的迭代器类型 +`_Vec` 是路径分量的容器, 它的迭代器类型与元素类型都交给 `auto` 推导, 无需写出具体类型 -### 用 decltype 复用另一个函数的返回类型:std::cbegin / std::cend +### decltype 取变量的类型:std::lower_bound 的二分查找 -更进一步, `std::cbegin` 干脆用 `decltype(_STD begin(_Cont))` 直接复用了 `begin` 的返回类型 —— 不必关心它到底是什么, 只要"和 begin 返回的一样"就行 +`decltype` 最直接的用法就是"取某个变量或表达式的类型"。标准库的二分查找 `std::lower_bound` 里, 先用 `auto` 推导出区间长度 `_Count`, 再用 `decltype(_Count)` 表示"与 `_Count` 相同的类型", 把 `_Count / 2` 转换回该类型: ```cpp -// MSVC STL · msvc-stl/stl/inc/xutility (有删节) -_EXPORT_STD template -_NODISCARD constexpr auto cbegin(const _Container& _Cont) noexcept(noexcept(_STD begin(_Cont))) - -> decltype(_STD begin(_Cont)) { - return _STD begin(_Cont); -} +// MSVC STL · msvc-stl/stl/inc/xutility (有删节) —— std::lower_bound + auto _UFirst = _STD _Get_unwrapped(_First); + auto _Count = _STD distance(_UFirst, _STD _Get_unwrapped(_Last)); + + while (0 < _Count) { // divide and conquer, find half that contains answer + const auto _Count2 = static_cast(_Count / 2); + const auto _UMid = _STD next(_UFirst, _Count2); + // ...(在 _UMid 处比较, 缩小区间, 略) + } ``` -> 小结: 面对"类型由模板参数决定、人手根本写不出来"的场景, 标准库用的正是本章这套 auto + decltype 工具。这也是 C++11 当初引入它们的核心动机之一 +这正是 `## 一`「声明定义」中 `decltype(b) b2` 的同款用法: `decltype(_Count)` 就是"`_Count` 的类型"。`auto` 负责把类型推导出来, `decltype` 负责在别处复用同一个类型 + +> 小结: 遍历容器、复用某个变量的类型 —— 这些日常写法在标准库内部用的正是本章这套 auto + decltype 工具。这也是 C++11 引入二者的核心动机之一 ## 三、注意事项 @@ -180,17 +185,21 @@ _NODISCARD constexpr auto cbegin(const _Container& _Cont) noexcept(noexcept(_STD > auto 推导会**剥离顶层 const 和引用**, 想保留得显式写 `const auto&` / `auto&`; decltype 则精确保留声明类型 ```cpp -const int ci = 1; -int n = 2; -int& ri = n; +int a = 1; +int &b = a; +const int c = 1; +const int &d = c; -auto a = ci; // int —— 顶层 const 被剥离 -auto b = ri; // int —— 引用被剥离, b 是 n 的独立副本 +auto a1 = a; // int +auto b1 = b; // int +auto c1 = c; // int +auto d1 = d; // int -const auto& r1 = ci; // const int& —— 用 const auto& 保留 -auto&& r2 = ci; // const int& —— 万能引用按需保留 +const auto c2 = c; // const int +const auto &d2 = d; // const int & -decltype(ci) d = ci; // const int —— decltype 精确保留 +decltype(c) c3 = c; // const int +decltype(d) d3 = d; // const int & ``` 这也解释了前面「类/结构体成员类型推导」里 `auto a = obj.a;` 为什么得到的是 `int` 而非 `const int` —— 顶层 const 被 auto 剥离了 diff --git a/videos/README.md b/videos/README.md index 15a3b5c..689baa7 100644 --- a/videos/README.md +++ b/videos/README.md @@ -2,12 +2,39 @@ ## 动画代码 -```python -# manim -pql videos/[cppxx]/[filename].py -manim -pql videos/cpp11/09-list-initialization.py +> Manim Community v0.18.1。manim 本体由 uv 装(纯 pip);pycairo/manimpango 的原生依赖 +> —— xcb-free 的 cairo/pango 图形栈 —— 用 xlings 装进项目 subos,免去系统 gcc 的 xcb 坑。 + +```bash +# 1. 一次性:装图形栈 + uv 进项目 subos(cairo/pango 的 deps 自动拉全树) +xlings install cairo pango uv + +# 2. 渲染:用启动器(已封装 PKG_CONFIG_PATH / uv 依赖 / pygments pin,免手输环境变量) +videos/render.sh cpp11/00-auto-and-decltype.py # 默认 -ql 快预览 +videos/render.sh cpp11/00-auto-and-decltype.py -qh # 高清 1080p +``` + +
+启动器封装了什么 / 手动等价命令 + +`videos/render.sh <场景> [manim参数]` 等价于(在仓库根执行): + +```bash +SR=$PWD/.xlings/subos/_/usr # 项目匿名 subos —— xlings install 装在这, xlings-gcc 默认也搜它 +PKG_CONFIG_PATH=$SR/lib/pkgconfig \ + uv run --with "manim==0.18.1" --with "pygments==2.17.2" \ + manim -ql videos/cpp11/00-auto-and-decltype.py ``` -> Note: Manim Community v0.18.1 +- `PKG_CONFIG_PATH` 指向项目 subos,让 pkg-config 命中 **xcb-free cairo**(而非宿主 apt 带 xcb 的)——仅首次/清缓存后编译 pycairo/manimpango 时需要,编好的 wheel 被 uv 缓存后可省。 +- `pygments==2.17.2` 避开 manim 0.18.1 的 `Code` 渲染 `#CCC` bug。 +- **兜底**(没装生态栈时,用系统 gcc 绕开 xlings-gcc 的 xcb 坑): + ```bash + CC=/usr/bin/gcc CXX=/usr/bin/g++ \ + uv run --with "manim==0.18.1" --with "pygments==2.17.2" \ + manim -ql videos/cpp11/00-auto-and-decltype.py + ``` +
## 视频列表 @@ -16,6 +43,7 @@ manim -pql videos/cpp11/09-list-initialization.py | **引导** | `项目使用教程/引导` | hello mcpp | [docs](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/base/chapter_1.md) / [code](/dslings/hello-mcpp.cpp) / [video](https://www.bilibili.com/video/BV182MtzPEiX?p=2) | | | **cpp11** | `00 - auto和decltype` | 类型自动推导 | [docs](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/00-auto-and-decltype.md) / [code](/dslings/cpp11/00-auto-and-decltype-0.cpp) / [video](https://www.bilibili.com/video/BV1xkdYYUEyH) | | | | | decltype注意事项 | [code](/dslings/cpp11/00-auto-and-decltype-4.cpp) / [video](https://www.bilibili.com/video/BV1KWoMYUEzW) | [补充](https://forum.d2learn.org/topic/82) | +| | | 类型自动推导 - 动画演示 | [code](/videos/cpp11/00-auto-and-decltype.py) / [video](https://www.bilibili.com/video/BV1EzJs6HEf7) | | | | `01 - default和delete` | 控制默认构造函数生成 | [code](/dslings/cpp11/01-default-and-delete-0.cpp) / [video](https://www.bilibili.com/video/BV1B35pz5EN2) | | | | | 类型对象行为控制示例 | [code](/dslings/cpp11/01-default-and-delete-1.cpp) / [video](https://www.bilibili.com/video/BV1Vg5tznE8o) | | | | `02 - override和final` | 重写显示意图和编译器检查 | [code](/dslings/cpp11/02-final-and-override-0.cpp) / [video](https://www.bilibili.com/video/BV1BdLJz6EKJ) | | diff --git a/videos/cpp11/00-auto-and-decltype.py b/videos/cpp11/00-auto-and-decltype.py index c28bffa..e70dc10 100644 --- a/videos/cpp11/00-auto-and-decltype.py +++ b/videos/cpp11/00-auto-and-decltype.py @@ -4,162 +4,468 @@ """ Manim Community v0.18.1 -# 用 uv 运行(无需预装 manim): -uv run --with "manim==0.18.1" manim -pql videos/cpp11/00-auto-and-decltype.py -uv run --with "manim==0.18.1" manim -pqh videos/cpp11/00-auto-and-decltype.py +# 最简 —— 用启动器(封装了下面所有环境变量),先 `xlings install cairo pango uv` 一次: +# videos/render.sh cpp11/00-auto-and-decltype.py # -ql 预览;加 -qh 出高清 +# +# 推荐 —— xlings 生态(无需系统 gcc):图形栈已发布到 xlings-res 并进官方索引 +# (deps 自动拉全树)。手动等价命令如下,详见 videos/README.md。 +# +# xlings install cairo pango # 装进项目匿名 subos _ (xlings-gcc 默认搜它) +# SR=$PWD/.xlings/subos/_/usr # 仓库根下的项目 subos, 不是全局 default +# PKG_CONFIG_PATH=$SR/lib/pkgconfig \ +# uv run --with "manim==0.18.1" --with "pygments==2.17.2" \ +# manim -ql videos/cpp11/00-auto-and-decltype.py # -ql 预览 / -qh 高清 +# +# 兜底 —— 没装生态栈时,用系统 gcc 绕开 xlings-gcc 的 xcb 坑: +# CC=/usr/bin/gcc CXX=/usr/bin/g++ uv run --with "manim==0.18.1" --with "pygments==2.17.2" manim -ql videos/cpp11/00-auto-and-decltype.py """ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) from d2x import * +from d2x import DHighlight class AutoAndDecltype(MovingCameraScene): def construct(self): - title, logo = mcpp_video_start(self, "{ auto / decltype }") + title, logo = mcpp_video_start(self, "{ 类型自动推导 }") + self.camera.frame.save_state() # 记录初始机位, 后面括号陷阱推近后拉回 self.wait(0.5) - self.play(Transform(title, Text("{ 类型自动推导 }", t2c={'类型自动推导': BLUE}))) + auto_text = Text("auto", color=BLUE).shift(UL * 2).scale(0.7) + decltype_text = Text("decltype", color=GREEN).shift(DR * 2).scale(0.7) + auto_demo_text = Text("auto func() -> int", color=PURPLE).shift(DL * 1.5).scale(0.5) + decltype_demo_text = Text("decltype(obj.data)", color=ORANGE).shift(UR * 1.5).scale(0.5) + + self.play( + LaggedStart( + ReplacementTransform(title.copy(), auto_text), + ReplacementTransform(title.copy(), decltype_text), + ReplacementTransform(title.copy(), auto_demo_text), + ReplacementTransform(title.copy(), decltype_demo_text), + lag_ratio=0.25, + ) + ) self.wait(0.5) # 场景1: 声明定义 —— auto 从初始值推导, decltype 取声明类型 - self.play(Transform(title, Text("{ 1 - 声明定义 }", t2c={'声明定义': BLUE}))) + self.play( + FadeOut(auto_text), + FadeOut(decltype_text), + FadeOut(auto_demo_text), + FadeOut(decltype_demo_text), + Transform(title, Text("{ 1 - 声明定义 }", t2c = { '声明定义': BLUE })) + ) - self.wait(0.5) + self.wait(0.3) - code1 = self.create_code_helper("""int b = 2; -auto b1 = b; // b1: int -decltype(b) b2 = b; // b2: int""") + # 显式类型声明 + explicit_code = self.create_code_helper( + 'int a = 1;\n' + 'double b = 2.0;\n' + 'char c = \'c\';' + ) - self.play(ReplacementTransform(title, code1)) + # 右: auto 版 + auto_code = self.create_code_helper( + 'auto a = 1;\n' + 'auto b = 2.0;\n' + 'auto c = \'c\';' + ).shift(RIGHT * 2.5) + label_l = Text("显式类型", color=GRAY, font_size=26).next_to(explicit_code, UP, buff=0.25) + label_r = Text("auto 推导", font_size=26).next_to(auto_code, UP, buff=0.25) + + # 先显明确的类型 + self.play( + ReplacementTransform(title, explicit_code), + FadeIn(label_l) + ) self.wait(0.5) - self.play(DHighlight(code1.code[1])) # auto: 从初始值推导 + # 高亮显式类型关键字 + self.play( + DHighlight(explicit_code.code[0][0:3], color=YELLOW), + DHighlight(explicit_code.code[1][0:6], color=YELLOW), + DHighlight(explicit_code.code[2][0:4], color=YELLOW), + ) self.wait(0.5) - self.play(DHighlight(code1.code[2])) # decltype: 取声明类型 + # 显示 auto 版本 + explicit_code = VGroup(explicit_code, label_l) + auto_code = VGroup(auto_code, label_r) + self.play( + ReplacementTransform(explicit_code.copy(), auto_code), + Transform(explicit_code, explicit_code.copy().scale(0.8).shift(LEFT * 2.5)) + ) self.wait(0.5) - # 场景2: 表达式类型推导 —— 保留计算精度 - title = Text("{ 2 - 表达式类型推导 }", t2c={'表达式': BLUE}) - self.play(ReplacementTransform(code1, title)) + auto_and_decltype_code = self.create_code_helper( + 'auto a = 1;\n' + 'auto b = 2.0;\n' + 'decltype(a) a1 = 1;\n' + 'decltype(2.0) b1 = 2.0;' + ).move_to(explicit_code) + + auto_and_decltype_code = VGroup( + auto_and_decltype_code, + Text("auto & decltype", color=BLUE, font_size=26).next_to(auto_and_decltype_code, UP, buff=0.25) + ) + + self.play( + Transform(auto_code, auto_code.copy().scale(0.8)), + ReplacementTransform(explicit_code, auto_and_decltype_code) + ) self.wait(0.5) - code2 = self.create_code_helper("""int a = 1; -auto x = a + 2 + 1.1; // double -decltype(a + 2 + 1.1) y = x; // double""") + auto_vs_type = self.create_code_helper( + 'std::string str = { "hello" };\n' + 'std::vector vec = { 1, 2, 3 };\n' + 'Rectangle rect = Rectangle { 1, 2 };\n' + '// --- \n' + 'auto str = std::string { "hello" };\n' + 'auto vec = std::vector { 1, 2, 3 };\n' + 'auto rect = Rectangle { 1, 2 };' + ) - self.play(ReplacementTransform(title, code2)) + self.play(ReplacementTransform(VGroup( + auto_and_decltype_code, + auto_code, + ), auto_vs_type)) self.wait(0.5) - self.play(DHighlight(code2.code[1], color=GREEN)) - self.play(DHighlight(code2.code[2], color=GREEN)) + + # 场景2: 表达式类型推导 + title = Text("{ 2 - 表达式类型推导 }", t2c={'表达式类型': BLUE}) + self.play(ReplacementTransform(auto_vs_type, title)) self.wait(0.5) - # 场景3: 复杂类型推导 —— auto 驯服冗长的迭代器类型(STL 真实场景) - title = Text("{ 3 - 复杂类型推导 }", t2c={'复杂类型': BLUE}) - self.play(ReplacementTransform(code2, title)) + code_expr = self.create_code_helper( + 'int a = 1;\n' + 'int b1 = a + 2 + 1.1;\n' + 'double b2 = a + 2 + 1.1;\n' + ) + + self.play(ReplacementTransform(title, code_expr)) self.wait(0.5) - code3a = self.create_code_helper("""std::vector v = {1, 2, 3}; -std::vector::iterator it = v.begin();""") + self.play( + DHighlight(code_expr.code[1][12:]), + DHighlight(code_expr.code[2][12:]) + ) - self.play(ReplacementTransform(title, code3a)) + self.wait(0.5) + b1_value_text = Text("4").next_to(code_expr, 2.5 * UL, buff=0.25).scale(0.5) + b2_value_text = Text("4.1").next_to(code_expr, 2.5 * DL, buff=0.25).scale(0.5) + b1_arrow_to_text = Arrow( + code_expr.code[1][7].get_left(), + b1_value_text.get_bottom(), + color=YELLOW, + stroke_width=2, + tip_length=0.1, + buff=0.05, + ).set_opacity(0.6) + + b2_arrow_to_text = Arrow( + code_expr.code[2][7].get_left(), + b2_value_text.get_top(), + color=YELLOW, + stroke_width=2, + tip_length=0.12, + buff=0.1, + ).set_opacity(0.6) + + expr_type_double_text = Text("表达式类型double").to_edge(0.2 * RIGHT).scale(0.4).set_color(PURE_RED) + self.play(Write(expr_type_double_text)) self.wait(0.5) - self.play(DHighlight(code3a.code[1], color=PURE_RED)) # 又长又难写 + self.play( + FadeIn(b1_value_text), + FadeIn(b2_value_text), + Create(b1_arrow_to_text), + Create(b2_arrow_to_text), + ) self.wait(0.5) - code3b = self.create_code_helper("""std::vector v = {1, 2, 3}; -auto it = v.begin();""") + auto_and_decltype_code = self.create_code_helper( + 'auto x = a + 2 + 1.1;\n' + 'decltype(a + 2 + 1.1) y = x;' + ) - self.play(ReplacementTransform(code3a, code3b)) + self.play(ReplacementTransform(VGroup( + code_expr, + b1_value_text, b2_value_text, + b1_arrow_to_text, b2_arrow_to_text, + expr_type_double_text, + ), auto_and_decltype_code)) + self.wait(0.5) + assert_type_code = self.create_code_helper( + 'auto c = \'0\' + 1;\n' + 'static_assert((std::is_same_v));' + ) + self.play(ReplacementTransform(auto_and_decltype_code, assert_type_code)) self.wait(0.5) + self.play(DHighlight(assert_type_code.code[1][35:36], color=PURE_RED, scale_factor=2)) - self.play(DHighlight(code3b.code[1], color=GREEN)) # auto 一步到位 + # 场景3: 复杂类型推导 + title = Text("{ 3 - 复杂类型推导 }", t2c={'复杂类型': BLUE}) + self.play(ReplacementTransform(assert_type_code, title)) self.wait(0.5) - # 场景4: 函数返回值类型推导 —— 后置返回 + decltype - title = Text("{ 4 - 函数返回值推导 }", t2c={'函数返回值': BLUE}) - self.play(ReplacementTransform(code3b, title)) + code_iterator = self.create_code_helper(""" +std::vector v = {1, 2, 3}; + +// std::vector::iterator it = v.begin(); +auto it = v.begin(); // 自动推导it类型 + +// decltype(v.begin()) it = v.begin(); +for (; it != v.end(); ++it) { + if (*it == 2) { + v.insert(it, 0); + break; + } +} +""") + code_iterator = VGroup(code_iterator, Text("STL 迭代器类型冗长难写").next_to(code_iterator, UP, buff=0.25).scale(0.5)) + code_iterator[0].code[2].set_color(GREEN) + code_iterator[0].code[5].set_color(GREEN) + + self.play(ReplacementTransform(title, code_iterator)) + self.wait(0.5) + self.play(DHighlight(code_iterator[0].code[2][3:30])) + self.wait(0.5) + self.play(DHighlight(code_iterator[0].code[3][0:5])) + self.wait(0.5) + self.play(DHighlight(code_iterator[0].code[5][3:23])) self.wait(0.5) - code4 = self.create_code_helper("""template -auto add(T1 a, T2 b) -> decltype(a + b) { + code_func_type = self.create_code_helper(""" +int add_func(int a, int b) { return a + b; -}""") +} - self.play(ReplacementTransform(title, code4)) +int main() { + auto minus_func = [](int a, int b) { return a - b; }; - self.wait(0.5) + std::vector> funcVec = { + add_func, + minus_func + }; - self.play(DHighlight(code4.code[1])) # auto ... -> decltype(a + b) + funcVec[0](1, 2); + funcVec[1](1, 2); +} +""") + code_func_type = VGroup(code_func_type, Text("函数类型和Lambda").next_to(code_func_type, UP, buff=0.25).scale(0.5)) + code_func_type.scale(0.85) + self.play(ReplacementTransform(code_iterator, code_func_type)) + self.wait(0.5) + self.play(DHighlight(code_func_type[0].code[5][22:])) + self.play(DHighlight(code_func_type[0].code[5][4:9])) + self.wait(0.5) + self.play(DHighlight(code_func_type[0].code[7][30:48])) self.wait(0.5) - # 场景5: 注意事项 —— auto 剥离 const / 引用, 想保留要显式写 - title = Text("{ 5 - const / 引用剥离 }", t2c={'const / 引用': PURE_RED}) - self.play(ReplacementTransform(code4, title)) + code_func_type[0].code[7][30:48].set_color(PURE_RED) + code_func_type[0].code[5][4:9].set_color(PURE_RED) + self.play( + code_func_type[0].code[7][30:48].animate.set_color(PURE_RED), + code_func_type[0].code[5][4:9].animate.set_color(PURE_RED) + ) + self.wait(0.5) + self.play(DHighlight(code_func_type[0].code[7][30:48], color=PURE_RED, scale_factor=1.5)) + self.wait(0.5) + self.play(DHighlight(code_func_type[0].code[5][4:9], color=PURE_RED, scale_factor=1.5)) + + # 场景4: 类体成员类型推导 + title = Text("{ 4 - 类成员类型推导 }", t2c={'类成员类型': BLUE}) + self.play(ReplacementTransform(code_func_type, title)) self.wait(0.5) - code5 = self.create_code_helper("""const int ci = 1; -auto a = ci; // int (const lost!) -const auto& r = ci; // const int& -decltype(ci) d = ci; // const int""") + code_class_member = self.create_code_helper(""" +struct Object { + const int a; + double b; + Object() : a(1), b(2.0) { } +}; + +int main() { + const Object obj; - self.play(ReplacementTransform(title, code5)) + auto a = obj.a; // auto -> int + std::vector vec; + // vector -> vector +}""") + code_class_member = VGroup(code_class_member, Text("类成员类型推导").next_to(code_class_member, UP, buff=0.25).scale(0.5)) + self.play(ReplacementTransform(title, code_class_member)) self.wait(0.5) - self.play(DHighlight(code5.code[1], color=PURE_RED)) # 顶层 const 被剥离 + self.play(DHighlight(code_class_member[0].code[9][20:])) + code_class_member[0].code[9][20:].set_color(YELLOW) + #self.play(DHighlight(code_class_member[0].code[11][4:])) + #code_class_member[0].code[11][4:].set_color(YELLOW) self.wait(0.5) - self.play(DHighlight(code5.code[2], color=GREEN)) # const auto& 保留 - self.play(DHighlight(code5.code[3], color=GREEN)) # decltype 精确保留 + # 场景5: 标准库STL示例 + title = Text("{ 5 - 标准库STL示例 }", t2c={'标准库STL': BLUE}) + self.play(ReplacementTransform(code_class_member, title)) + self.wait(0.5) + + code_filesystem_iterator_1 = self.create_code_helper(""" +// MSVC STL · msvc-stl/stl/inc/filesystem +auto _New_end = _Vec.begin(); +for (auto _Pos = _Vec.begin(); _Pos != _Vec.end();) { + const auto _Elem = *_Pos++; + // ...(根据 _Elem 决定是否写回 _New_end, 略) +} +""") + code_filesystem_iterator_1.code[0].set_color(GREEN) + code_filesystem_iterator_1 = VGroup(code_filesystem_iterator_1, Text("auto 推导迭代器与元素类型").next_to(code_filesystem_iterator_1, UP, buff=0.25).scale(0.5)) + self.play(ReplacementTransform(title, code_filesystem_iterator_1)) self.wait(0.5) - # 场景6: 注意事项 —— decltype 的括号陷阱 - title = Text("{ 6 - decltype 括号陷阱 }", t2c={'括号陷阱': PURE_RED}) - self.play(ReplacementTransform(code5, title)) + code_lower_bound = self.create_code_helper(""" +// MSVC STL · msvc-stl/stl/inc/xutility — std::lower_bound +auto _UFirst = _STD _Get_unwrapped(_First); +auto _Count = _STD distance(_UFirst, _STD _Get_unwrapped(_Last)); +while (0 < _Count) { // divide and conquer, find half that contains answer + const auto _Count2 = static_cast(_Count / 2); + const auto _UMid = _STD next(_UFirst, _Count2); + // ...(在 _UMid 处比较, 缩小区间, 略) +} +""") + code_lower_bound.code[1].set_color(GREEN) + + code_lower_bound = VGroup(code_lower_bound, Text("decltype 取变量的类型").next_to(code_lower_bound, UP, buff=0.25).scale(0.5)) + + code_lower_bound.scale(0.8) + + self.play(ReplacementTransform(code_filesystem_iterator_1, code_lower_bound)) + self.wait(0.5) + + code_lower_bound[0].code[5][37:53].set_color(PURE_RED) + self.play(DHighlight(code_lower_bound[0].code[5][37:53], color=PURE_RED)) + self.wait(0.5) + + # 场景6: 注意事项 + title = Text("{ 6 - 注意事项 }", t2c={'注意事项': BLUE}) + self.play(ReplacementTransform(code_lower_bound, title)) self.wait(0.5) - code6 = self.create_code_helper("""int a = 1; -decltype(a) b; // int -decltype((a)) c; // int&""") + code_auto_const_ref = self.create_code_helper(""" +int a = 1; +int &b = a; +const int c = 1; +const int &d = c; + +auto a1 = a; // int +auto b1 = b; // int +auto c1 = c; // int +auto d1 = d; // int +""") + self.play(ReplacementTransform(title, code_auto_const_ref)) + self.wait(0.5) - self.play(ReplacementTransform(title, code6)) + for line_id in range(5, 9): + code_auto_const_ref.code[line_id][13:].set_color(PURE_RED) + self.play(DHighlight(code_auto_const_ref.code[line_id][13:], color=PURE_RED), run_time=0.25) + self.wait(0.5) + code_save_const_ref = self.create_code_helper(""" +const auto c2 = c; // const int +const auto &d2 = d; // const int & + +decltype(c) c3 = c; // const int +decltype(d) d3 = d; // const int & +""") + code_save_const_ref.shift(RIGHT * 2.5).scale(0.8) + code_auto_const_ref_copy = code_auto_const_ref.copy() + self.play( + ReplacementTransform(code_auto_const_ref_copy, code_save_const_ref), + code_auto_const_ref.animate.shift(LEFT * 3.5).scale(0.6) + ) self.wait(0.5) - self.play(DHighlight(code6.code[1])) # decltype(a): 声明类型 int + for line_id in range(0, 5): + code_save_const_ref.code[line_id][21:].set_color(GREEN) + self.play(DHighlight(code_save_const_ref.code[line_id][21:], color=GREEN), run_time=0.25) self.wait(0.5) - select_box = SurroundingRectangle(code6.code[2], color=PURE_RED, buff=0.1) - self.play(Create(select_box)) - self.play(DHighlight(code6.code[2], color=PURE_RED)) # decltype((a)): 左值表达式 -> int& + code_decltype_note1 = self.create_code_helper(""" +int a = 1; +decltype(a) b; // 推导结果为a的声明类型int +decltype( (a) ) c = a; // 推导结果为(a)这个左值表达式的类型 int & +""") + code_decltype_note1.scale(0.8) + self.play(ReplacementTransform( + VGroup(code_save_const_ref, code_auto_const_ref), + code_decltype_note1 + )) + + for line_id in range(1, 3): + code_decltype_note1.code[line_id][22:].set_color(PURE_RED) + self.play(DHighlight(code_decltype_note1.code[line_id][22:], color=PURE_RED), run_time=0.25) self.wait(0.5) - mcpp_video_end(self, logo, VGroup(code6, select_box)) + code_decltype_note2 = self.create_code_helper(""" +struct Object { + const int a; + double b; + Object() : a(1), b(2.0) { } +}; + +int main() { + Object obj; + const Object obj1; + + decltype(obj.b) // double + decltype(obj1.b) // double + + decltype( (obj.b) ) // double & + + // 受obj1定义的const修饰影响, 所以是 const double & + decltype( (obj1.b) ) +} +""") + code_decltype_note3 = self.create_code_helper(""" +int &&b = 1; + +decltype(b) // 推导结果是声明类型 int && +decltype( (b) ) // 推导结果是 int & +""") + + code_decltype_note2.code[15].set_color(PURE_RED) + code_decltype_note3.code[2][16:].set_color(PURE_RED) + code_decltype_note3.code[3][16:].set_color(PURE_RED) + code_decltype_note2.scale(0.8) + + self.play(ReplacementTransform(code_decltype_note1, code_decltype_note2)) + self.wait(0.5) + self.play(ReplacementTransform(code_decltype_note2, code_decltype_note3)) + self.wait(0.5) + + mcpp_video_end(self, logo, VGroup(code_decltype_note2, code_decltype_note3)) @staticmethod def create_code_helper(code: str): diff --git a/videos/d2x/video.py b/videos/d2x/video.py index 3e35dfb..596355c 100644 --- a/videos/d2x/video.py +++ b/videos/d2x/video.py @@ -30,7 +30,7 @@ def mcpp_video_end(scene, logo, obj_group=VGroup()): ending = VGroup( Text("开源交互式教程", color=RED).scale(0.9), - Tex(r"\textit{\underline{https://github.com/mcpp-community/d2mcpp}}"), + Tex(r"\textit{\underline{github.com/mcpp-community/d2mcpp}}"), ).arrange(DOWN, buff=0.15).scale(0.8) scene.play( diff --git a/videos/render.sh b/videos/render.sh new file mode 100755 index 0000000..0c505c0 --- /dev/null +++ b/videos/render.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +# d2mcpp 动画渲染启动器 —— 封装 PKG_CONFIG_PATH(项目 subos)+ uv 依赖 pin,免手输环境变量。 +# +# 用法: +# videos/render.sh <场景> # 默认 -ql 快预览 +# videos/render.sh <场景> -qh # 高清 1080p +# videos/render.sh <场景> -qh -p # 高清 + 渲染完自动打开 +# <场景> 可写相对 videos/ 的路径或完整路径,例: +# videos/render.sh cpp11/00-auto-and-decltype.py +# videos/render.sh videos/cpp11/09-list-initialization.py -qh +# +# 前置(一次性,把 xcb-free 图形栈 + uv 装进项目 subos): +# xlings install cairo pango uv +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +cd "$REPO_ROOT" + +if [[ $# -lt 1 ]]; then + echo "用法: videos/render.sh <场景.py> [manim 参数, 默认 -ql]" >&2 + exit 2 +fi +SCENE="$1"; shift +[[ -f "$SCENE" ]] || SCENE="videos/$SCENE" # 允许省略开头的 videos/ +[[ -f "$SCENE" ]] || { echo "找不到场景文件: $1" >&2; exit 1; } + +# manim 参数:默认 -ql(快预览),用户传了就用用户的(如 -qh / -pqh) +MANIM_ARGS=("$@"); [[ ${#MANIM_ARGS[@]} -gt 0 ]] || MANIM_ARGS=(-ql) + +# 项目匿名 subos sysroot —— xlings install cairo pango 装在这, xlings-gcc 默认也搜它 +SR="$REPO_ROOT/.xlings/subos/_/usr" +if [[ ! -f "$SR/lib/pkgconfig/cairo.pc" ]]; then + echo "[render] 警告: 项目 subos 里没找到 cairo —— 先跑: xlings install cairo pango uv" >&2 + echo "[render] (没装生态栈时也可在命令前加 CC=/usr/bin/gcc CXX=/usr/bin/g++ 兜底)" >&2 +fi +export PKG_CONFIG_PATH="$SR/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}" +export LD_LIBRARY_PATH="$SR/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" + +echo "[render] scene = $SCENE args = ${MANIM_ARGS[*]}" +# manim 本体 + pygments(pin 2.17.2 避开 0.18.1 的 Code 渲染 #CCC bug)由 uv 临时装 +exec uv run --with "manim==0.18.1" --with "pygments==2.17.2" manim "${MANIM_ARGS[@]}" "$SCENE" From a12f8c0e65bd0438cacde452b5290444b121f3ff Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 14 Jun 2026 10:23:21 +0800 Subject: [PATCH 3/3] =?UTF-8?q?docs(cpp11/00):=20correct=20video=20labels?= =?UTF-8?q?=20=E2=80=94=20=E8=A7=86=E9=A2=91=E8=A7=A3=E8=AF=BB=3DBV1EzJs6H?= =?UTF-8?q?Ef7,=20=E7=BB=83=E4=B9=A0=E8=AE=B2=E8=A7=A3=3DBV1xkdYYUEyH?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- book/en/src/cpp11/00-auto-and-decltype.md | 2 +- book/src/cpp11/00-auto-and-decltype.md | 2 +- videos/README.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/book/en/src/cpp11/00-auto-and-decltype.md b/book/en/src/cpp11/00-auto-and-decltype.md index 343a3eb..b013da0 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/BV1xkdYYUEyH) / [Animation](https://www.bilibili.com/video/BV1EzJs6HEf7) | [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/dslings/cpp11/00-auto-and-decltype-0.cpp) | | **Why were they introduced?** diff --git a/book/src/cpp11/00-auto-and-decltype.md b/book/src/cpp11/00-auto-and-decltype.md index 293e330..50b8586 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/BV1xkdYYUEyH) / [动画演示](https://www.bilibili.com/video/BV1EzJs6HEf7) | [练习代码](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/dslings/cpp11/00-auto-and-decltype-0.cpp) | | **为什么引入?** diff --git a/videos/README.md b/videos/README.md index 689baa7..df941c8 100644 --- a/videos/README.md +++ b/videos/README.md @@ -41,9 +41,9 @@ PKG_CONFIG_PATH=$SR/lib/pkgconfig \ | c++标准 | 特性 | 标题 | 练习代码/视频 | 备注 | | --- | --- | --- | --- | --- | | **引导** | `项目使用教程/引导` | hello mcpp | [docs](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/base/chapter_1.md) / [code](/dslings/hello-mcpp.cpp) / [video](https://www.bilibili.com/video/BV182MtzPEiX?p=2) | | -| **cpp11** | `00 - auto和decltype` | 类型自动推导 | [docs](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/00-auto-and-decltype.md) / [code](/dslings/cpp11/00-auto-and-decltype-0.cpp) / [video](https://www.bilibili.com/video/BV1xkdYYUEyH) | | +| **cpp11** | `00 - auto和decltype` | 类型自动推导 | [docs](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp11/00-auto-and-decltype.md) / [code](/videos/cpp11/00-auto-and-decltype.py) / [video](https://www.bilibili.com/video/BV1EzJs6HEf7) | | +| | | 练习讲解 | [code](/dslings/cpp11/00-auto-and-decltype-0.cpp) / [video](https://www.bilibili.com/video/BV1xkdYYUEyH) | | | | | decltype注意事项 | [code](/dslings/cpp11/00-auto-and-decltype-4.cpp) / [video](https://www.bilibili.com/video/BV1KWoMYUEzW) | [补充](https://forum.d2learn.org/topic/82) | -| | | 类型自动推导 - 动画演示 | [code](/videos/cpp11/00-auto-and-decltype.py) / [video](https://www.bilibili.com/video/BV1EzJs6HEf7) | | | | `01 - default和delete` | 控制默认构造函数生成 | [code](/dslings/cpp11/01-default-and-delete-0.cpp) / [video](https://www.bilibili.com/video/BV1B35pz5EN2) | | | | | 类型对象行为控制示例 | [code](/dslings/cpp11/01-default-and-delete-1.cpp) / [video](https://www.bilibili.com/video/BV1Vg5tznE8o) | | | | `02 - override和final` | 重写显示意图和编译器检查 | [code](/dslings/cpp11/02-final-and-override-0.cpp) / [video](https://www.bilibili.com/video/BV1BdLJz6EKJ) | |