From 008e333a7617fa106871505c6cd8c050d72514ce Mon Sep 17 00:00:00 2001 From: li-zhou <2181719471@qq.com> Date: Fri, 19 Jun 2026 23:39:13 +0800 Subject: [PATCH 1/2] docs(cpp14): add 01-relaxed-constexpr book chapter and build wiring --- book/en/src/SUMMARY.md | 1 + book/en/src/cpp14/01-relaxed-constexpr.md | 178 ++++++++++++++++++++++ book/src/SUMMARY.md | 1 + book/src/cpp14/01-relaxed-constexpr.md | 178 ++++++++++++++++++++++ dslings/cpp14/xmake.lua | 8 + dslings/en/cpp14/xmake.lua | 10 ++ solutions/cpp14/xmake.lua | 10 ++ 7 files changed, 386 insertions(+) create mode 100644 book/en/src/cpp14/01-relaxed-constexpr.md create mode 100644 book/src/cpp14/01-relaxed-constexpr.md diff --git a/book/en/src/SUMMARY.md b/book/en/src/SUMMARY.md index b2008be..b7bf161 100644 --- a/book/en/src/SUMMARY.md +++ b/book/en/src/SUMMARY.md @@ -31,6 +31,7 @@ # C++14 Core Language Features - [Generic Lambdas](./cpp14/00-generic-lambdas.md) +- [Relaxed constexpr](./cpp14/01-relaxed-constexpr.md) # Additional Resources diff --git a/book/en/src/cpp14/01-relaxed-constexpr.md b/book/en/src/cpp14/01-relaxed-constexpr.md new file mode 100644 index 0000000..2c5a89f --- /dev/null +++ b/book/en/src/cpp14/01-relaxed-constexpr.md @@ -0,0 +1,178 @@ +
+ + 🌎 [中文] | [English] +
+ +[中文]: ../../cpp14/01-relaxed-constexpr.html +[English]: ./01-relaxed-constexpr.html + +# Relaxed constexpr + +C++14 significantly relaxed the restrictions on `constexpr` functions — loops, branches, local variables, and multiple statements are now allowed, enabling far more algorithms to execute at compile time + +| Book | Video | Code | X | +| --- | --- | --- | --- | +| [cppreference-constexpr](https://en.cppreference.com/w/cpp/language/constexpr) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp14/01-relaxed-constexpr.md) | [Video Explanation]() | [Exercise Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp14/01-relaxed-constexpr-0.cpp) | | + + +**Why introduced?** + +- In C++11, a `constexpr` function body was restricted to a single `return expr;` statement — any loop or branch had to be expressed via recursion and the ternary operator, making the code obscure +- Loops and branches are the most fundamental control flow in practical algorithms; excluding them from constexpr severely limited the scope of compile-time computation +- C++14 allows `for` / `while` / `if` / `switch` and local variables in constexpr functions, making it possible to move runtime algorithms to compile time without rewriting their style + +**C++11 vs C++14 constexpr** + +```cpp +// C++11: recursion + ternary operator +constexpr int factorial_11(int n) { + return n <= 1 ? 1 : n * factorial_11(n - 1); +} + +// C++14: plain loop +constexpr int factorial_14(int n) { + int result = 1; + for (int i = 1; i <= n; ++i) { + result *= i; + } + return result; +} +``` + +## I. Basic Usage and Scenarios + +### Loop Structures — for / while + +> constexpr functions can use loops just like normal functions + +```cpp +constexpr int sum_to(int n) { + int total = 0; + for (int i = 1; i <= n; ++i) { + total += i; + } + return total; +} + +static_assert(sum_to(5) == 15, ""); +static_assert(sum_to(100) == 5050, ""); +``` + +### Branch Structures — if / switch + +```cpp +constexpr int abs_val(int x) { + if (x < 0) { + return -x; + } + return x; +} + +static_assert(abs_val(-42) == 42, ""); +static_assert(abs_val(0) == 0, ""); + +constexpr int day_count(int month) { + switch (month) { + case 1: case 3: case 5: case 7: case 8: case 10: case 12: + return 31; + case 4: case 6: case 9: case 11: + return 30; + case 2: + return 28; + default: + return 0; + } +} + +static_assert(day_count(7) == 31, ""); +``` + +### Local Variables and Multiple Statements + +```cpp +constexpr double circle_area(double radius) { + const double pi = 3.14159; + double r2 = radius * radius; + return pi * r2; +} + +static_assert(circle_area(1.0) == 3.14159, ""); +``` + +### Practical Compile-Time Algorithm — Loop-Based Fibonacci + +> Replace recursion with a loop to compute fibonacci at compile time + +```cpp +constexpr int fib(int n) { + int a = 0, b = 1; + for (int i = 0; i < n; ++i) { + int tmp = a + b; + a = b; + b = tmp; + } + return a; +} + +static_assert(fib(10) == 55, ""); +static_assert(fib(0) == 0, ""); +``` + +## II. Notes + +### Operations Still Banned in C++14 constexpr + +The following operations remain forbidden in C++14 constexpr functions: + +- `goto` statements +- `try` / `catch` exception handling +- `static` or `thread_local` local variables +- inline assembly +- uninitialized local variables + +### The "Dual Nature" of constexpr Functions + +A constexpr function can execute at compile time or at runtime — depending on the call context: + +```cpp +constexpr int fib(int n) { + int a = 0, b = 1; + for (int i = 0; i < n; ++i) { + int tmp = a + b; + a = b; + b = tmp; + } + return a; +} + +static_assert(fib(10) == 55, ""); // compile-time + +int main() { + int n = std::rand() % 20; + return fib(n); // runtime — same code +} +``` + +### constexpr Is Not a Drop-In Replacement for inline + +A constexpr specifier does not change the ODR linkage in C++14 (C++17 later made constexpr functions implicitly inline), nor does it mean every function that can be constexpr should be. If a function is almost always called at runtime, adding constexpr increases the interface constraint with little practical benefit + +## III. Exercise Code + +### Exercise Code Topics + +- 0 - [constexpr Loops — Compile-Time Factorial and Power](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp14/01-relaxed-constexpr-0.cpp) +- 1 - [constexpr Branches and Local Variables — Compile-Time Conditionals and Fibonacci](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp14/01-relaxed-constexpr-1.cpp) + +### Exercise Auto-Checker Command + +``` +d2x checker relaxed-constexpr +``` + +## IV. Other + +- [Discussion Forum](https://forum.d2learn.org/category/20) +- [d2mcpp Tutorial Repository](https://github.com/mcpp-community/d2mcpp) +- [Tutorial Video List](https://space.bilibili.com/65858958/lists/5208246) +- [Tutorial Support Tool - xlings](https://github.com/openxlings/xlings) diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 7efe83a..49505de 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -31,6 +31,7 @@ # C++14核心语言特性 - [泛型 lambda - generic lambdas](./cpp14/00-generic-lambdas.md) +- [放宽的 constexpr - relaxed constexpr](./cpp14/01-relaxed-constexpr.md) # 其他 diff --git a/book/src/cpp14/01-relaxed-constexpr.md b/book/src/cpp14/01-relaxed-constexpr.md new file mode 100644 index 0000000..ed06d30 --- /dev/null +++ b/book/src/cpp14/01-relaxed-constexpr.md @@ -0,0 +1,178 @@ +
+ + 🌎 [中文] | [English] +
+ +[中文]: ./01-relaxed-constexpr.html +[English]: ../en/cpp14/01-relaxed-constexpr.html + +# 放宽的 constexpr - relaxed constexpr + +C++14 大幅放宽了 `constexpr` 函数的限制——允许在编译期函数中使用循环、分支、局部变量和多条语句, 让更多的算法可以在编译期执行 + +| Book | Video | Code | X | +| --- | --- | --- | --- | +| [cppreference-constexpr](https://en.cppreference.com/w/cpp/language/constexpr) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp14/01-relaxed-constexpr.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp14/01-relaxed-constexpr-0.cpp) | | + + +**为什么引入?** + +- C++11 的 `constexpr` 函数体必须是 `return expr;` 一条语句, 任何循环或分支都要用递归 + 三元运算符表达, 代码晦涩 +- 实际算法中循环和分支是最基本的控制流, 将它们排除在 constexpr 之外严重限制了编译期计算的应用范围 +- C++14 允许 constexpr 函数使用 `for` / `while` / `if` / `switch` 和局部变量, 让"把运行期算法搬到编译期"成为可能, 而不需要改写风格 + +**C++11 vs C++14 constexpr** + +```cpp +// C++11: 只能用递归 + 三元运算符 +constexpr int factorial_11(int n) { + return n <= 1 ? 1 : n * factorial_11(n - 1); +} + +// C++14: 可以写正常的循环 +constexpr int factorial_14(int n) { + int result = 1; + for (int i = 1; i <= n; ++i) { + result *= i; + } + return result; +} +``` + +## 一、基础用法和场景 + +### 循环结构 — for / while + +> constexpr 函数中可以像普通函数一样写循环 + +```cpp +constexpr int sum_to(int n) { + int total = 0; + for (int i = 1; i <= n; ++i) { + total += i; + } + return total; +} + +static_assert(sum_to(5) == 15, ""); +static_assert(sum_to(100) == 5050, ""); +``` + +### 分支结构 — if / switch + +```cpp +constexpr int abs_val(int x) { + if (x < 0) { + return -x; + } + return x; +} + +static_assert(abs_val(-42) == 42, ""); +static_assert(abs_val(0) == 0, ""); + +constexpr int day_count(int month) { + switch (month) { + case 1: case 3: case 5: case 7: case 8: case 10: case 12: + return 31; + case 4: case 6: case 9: case 11: + return 30; + case 2: + return 28; + default: + return 0; + } +} + +static_assert(day_count(7) == 31, ""); +``` + +### 局部变量与多条语句 + +```cpp +constexpr double circle_area(double radius) { + const double pi = 3.14159; + double r2 = radius * radius; + return pi * r2; +} + +static_assert(circle_area(1.0) == 3.14159, ""); +``` + +### 编译期实用算法 — 循环斐波那契 + +> 用循环替代递归, 在编译期计算斐波那契数列 + +```cpp +constexpr int fib(int n) { + int a = 0, b = 1; + for (int i = 0; i < n; ++i) { + int tmp = a + b; + a = b; + b = tmp; + } + return a; +} + +static_assert(fib(10) == 55, ""); +static_assert(fib(0) == 0, ""); +``` + +## 二、注意事项 + +### C++14 constexpr 仍不支持的操作 + +以下操作在 C++14 constexpr 函数中仍被禁止: + +- `goto` 语句 +- `try` / `catch` 异常处理 +- `static` 或 `thread_local` 局部变量 +- 内联汇编 +- 未初始化的局部变量 + +### constexpr 函数的"两面性" + +constexpr 函数可以在编译期执行, 也可以在运行期执行——取决于调用上下文: + +```cpp +constexpr int fib(int n) { + int a = 0, b = 1; + for (int i = 0; i < n; ++i) { + int tmp = a + b; + a = b; + b = tmp; + } + return a; +} + +static_assert(fib(10) == 55, ""); // 编译期执行 + +int main() { + int n = std::rand() % 20; + return fib(n); // 运行期执行, 同一份代码 +} +``` + +### constexpr 不是 inline 的替代 + +把函数标记为 constexpr 并不改变其 ODR 链接属性 (C++17 起 constexpr 函数才隐式 inline), 也不代表所有能 constexpr 的都该 constexpr。如果一个函数几乎只在运行期调用, 加 constexpr 只增加了接口约束, 实际收益很小 + +## 三、练习代码 + +### 练习代码主题 + +- 0 - [constexpr 循环 — 编译期阶乘和幂运算](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp14/01-relaxed-constexpr-0.cpp) +- 1 - [constexpr 分支和局部变量 — 编译期条件判断与斐波那契](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp14/01-relaxed-constexpr-1.cpp) + +### 练习代码自动检测命令 + +``` +d2x checker relaxed-constexpr +``` + +## 四、其他 + +- [交流讨论](https://forum.d2learn.org/category/20) +- [d2mcpp教程仓库](https://github.com/mcpp-community/d2mcpp) +- [教程视频列表](https://space.bilibili.com/65858958/lists/5208246) +- [教程支持工具-xlings](https://github.com/openxlings/xlings) diff --git a/dslings/cpp14/xmake.lua b/dslings/cpp14/xmake.lua index 8a21cbf..c81e448 100644 --- a/dslings/cpp14/xmake.lua +++ b/dslings/cpp14/xmake.lua @@ -9,3 +9,11 @@ target("cpp14-00-generic-lambdas-0") target("cpp14-00-generic-lambdas-1") set_kind("binary") add_files("00-generic-lambdas-1.cpp") + +target("cpp14-01-relaxed-constexpr-0") + set_kind("binary") + add_files("01-relaxed-constexpr-0.cpp") + +target("cpp14-01-relaxed-constexpr-1") + set_kind("binary") + add_files("01-relaxed-constexpr-1.cpp") diff --git a/dslings/en/cpp14/xmake.lua b/dslings/en/cpp14/xmake.lua index 8a21cbf..935aece 100644 --- a/dslings/en/cpp14/xmake.lua +++ b/dslings/en/cpp14/xmake.lua @@ -9,3 +9,13 @@ target("cpp14-00-generic-lambdas-0") target("cpp14-00-generic-lambdas-1") set_kind("binary") add_files("00-generic-lambdas-1.cpp") + +-- target: cpp14-01-relaxed-constexpr + +target("cpp14-01-relaxed-constexpr-0") + set_kind("binary") + add_files("01-relaxed-constexpr-0.cpp") + +target("cpp14-01-relaxed-constexpr-1") + set_kind("binary") + add_files("01-relaxed-constexpr-1.cpp") diff --git a/solutions/cpp14/xmake.lua b/solutions/cpp14/xmake.lua index 8bbbb90..030c95d 100644 --- a/solutions/cpp14/xmake.lua +++ b/solutions/cpp14/xmake.lua @@ -9,3 +9,13 @@ target("cpp14-00-generic-lambdas-0-ref") target("cpp14-00-generic-lambdas-1-ref") set_kind("binary") add_files("00-generic-lambdas-1.cpp") + +-- target: cpp14-01-relaxed-constexpr + +target("cpp14-01-relaxed-constexpr-0-ref") + set_kind("binary") + add_files("01-relaxed-constexpr-0.cpp") + +target("cpp14-01-relaxed-constexpr-1-ref") + set_kind("binary") + add_files("01-relaxed-constexpr-1.cpp") From 9004bbe10a0c3f275d3d8be26638a81e8d1a5135 Mon Sep 17 00:00:00 2001 From: li-zhou <2181719471@qq.com> Date: Fri, 19 Jun 2026 23:39:30 +0800 Subject: [PATCH 2/2] feat(cpp14): add 01-relaxed-constexpr exercises and solutions --- book/en/src/cpp14/01-relaxed-constexpr.md | 50 +++++++++++- book/src/cpp14/01-relaxed-constexpr.md | 50 +++++++++++- dslings/cpp14/01-relaxed-constexpr-0.cpp | 68 ++++++++++++++++ dslings/cpp14/01-relaxed-constexpr-1.cpp | 86 +++++++++++++++++++++ dslings/en/cpp14/01-relaxed-constexpr-0.cpp | 68 ++++++++++++++++ dslings/en/cpp14/01-relaxed-constexpr-1.cpp | 86 +++++++++++++++++++++ solutions/cpp14/01-relaxed-constexpr-0.cpp | 49 ++++++++++++ solutions/cpp14/01-relaxed-constexpr-1.cpp | 65 ++++++++++++++++ 8 files changed, 516 insertions(+), 6 deletions(-) create mode 100644 dslings/cpp14/01-relaxed-constexpr-0.cpp create mode 100644 dslings/cpp14/01-relaxed-constexpr-1.cpp create mode 100644 dslings/en/cpp14/01-relaxed-constexpr-0.cpp create mode 100644 dslings/en/cpp14/01-relaxed-constexpr-1.cpp create mode 100644 solutions/cpp14/01-relaxed-constexpr-0.cpp create mode 100644 solutions/cpp14/01-relaxed-constexpr-1.cpp diff --git a/book/en/src/cpp14/01-relaxed-constexpr.md b/book/en/src/cpp14/01-relaxed-constexpr.md index 2c5a89f..b606dd7 100644 --- a/book/en/src/cpp14/01-relaxed-constexpr.md +++ b/book/en/src/cpp14/01-relaxed-constexpr.md @@ -118,7 +118,51 @@ static_assert(fib(10) == 55, ""); static_assert(fib(0) == 0, ""); ``` -## II. Notes +## II. Real-World Case — Compile-Time Index Sequences in the STL + +> C++14 introduced `std::integer_sequence` and `std::make_index_sequence`, which rely on relaxed constexpr for compile-time integer generation. The examples below cite the vendored [MSVC STL](https://github.com/mcpp-community/d2mcpp/tree/main/msvc-stl) (source: [`msvc-stl/stl/inc/tuple`](https://github.com/mcpp-community/d2mcpp/blob/main/msvc-stl/stl/inc/tuple#L323-L343)); `_Tag` / `_Tpl` are internal tags and types and can be ignored while reading + +### std::tuple Compile-Time Construction — index_sequence Unfolds Parameter Packs + +`std::tuple` must extract elements one by one from a tuple-like object and construct its own members — this process must happen at compile time. MSVC STL uses `make_index_sequence` to generate compile-time indices and expand parameter packs: + +```cpp +// MSVC STL · msvc-stl/stl/inc/tuple (abridged) +template +constexpr tuple(_Tag, _Tpl&& _Right, index_sequence<_Indices...>) + : _Mybase(static_cast<_Tpl&&>(_Right)._Get_rest()) { + // _Indices... is a compile-time-generated sequence 0, 1, 2, ... N-1 + // Elements are extracted via get<_Indices>(_Right) one by one +} + +// Public constructor — uses make_index_sequence to auto-generate indices +explicit(false) constexpr tuple(_Exact_args_t, _Tpl&& _Right) + : tuple(_Tag{}, _STD forward<_Tpl>(_Right), + make_index_sequence>>{}) {} +``` + +`make_index_sequence` generates `index_sequence<0, 1, ..., N-1>` at compile time, enabling the tuple constructor to extract elements via `get<0>` / `get<1>` / ... sequentially. This is the canonical post-C++14 constexpr pattern — iteration is not a runtime concept but achieved through compile-time integer sequences and pack expansion + +### std::integer_sequence — the C++14 Compile-Time Integer Carrier + +```cpp +// MSVC STL · msvc-stl/stl/inc/utility (abridged) +template +struct integer_sequence { + static_assert(is_integral_v<_Ty>, + "integer_sequence requires T to be an integral type."); +}; + +template +using index_sequence = integer_sequence; + +template +using make_index_sequence = __make_integer_seq; +``` + +> Summary: Both `std::make_index_sequence` and `std::tuple`'s compile-time construction depend on the relaxed constexpr environment introduced in C++14. Without constexpr that supports loops and branches, the standard library would rely entirely on compiler internals for integer sequence generation rather than on the expressive power of the C++ language itself + +## III. Notes ### Operations Still Banned in C++14 constexpr @@ -157,7 +201,7 @@ int main() { A constexpr specifier does not change the ODR linkage in C++14 (C++17 later made constexpr functions implicitly inline), nor does it mean every function that can be constexpr should be. If a function is almost always called at runtime, adding constexpr increases the interface constraint with little practical benefit -## III. Exercise Code +## IV. Exercise Code ### Exercise Code Topics @@ -170,7 +214,7 @@ A constexpr specifier does not change the ODR linkage in C++14 (C++17 later made d2x checker relaxed-constexpr ``` -## IV. Other +## V. Other - [Discussion Forum](https://forum.d2learn.org/category/20) - [d2mcpp Tutorial Repository](https://github.com/mcpp-community/d2mcpp) diff --git a/book/src/cpp14/01-relaxed-constexpr.md b/book/src/cpp14/01-relaxed-constexpr.md index ed06d30..698f2a3 100644 --- a/book/src/cpp14/01-relaxed-constexpr.md +++ b/book/src/cpp14/01-relaxed-constexpr.md @@ -118,7 +118,51 @@ static_assert(fib(10) == 55, ""); static_assert(fib(0) == 0, ""); ``` -## 二、注意事项 +## 二、真实案例 - STL 中的 constexpr 编译期索引序列 + +> C++14 同步引入了 `std::integer_sequence` 和 `std::make_index_sequence`, 它们正是依赖放宽后的 constexpr 才能实现的编译期工具。下面以仓库内置的 [MSVC STL](https://github.com/mcpp-community/d2mcpp/tree/main/msvc-stl) 为例 (源码: [`msvc-stl/stl/inc/tuple`](https://github.com/mcpp-community/d2mcpp/blob/main/msvc-stl/stl/inc/tuple#L323-L343)), `_Tag` / `_Tpl` 是库内部标记和类型, 阅读时可忽略 + +### std::tuple 的编译期构造 — index_sequence 展开参数包 + +`std::tuple` 需要从一个"类元组"对象中逐元素提取并构造自己的成员, 这个过程必须在编译期完成。MSVC STL 使用 `make_index_sequence` 生成编译期索引, 配合参数包展开实现: + +```cpp +// MSVC STL · msvc-stl/stl/inc/tuple (有删节) +template +constexpr tuple(_Tag, _Tpl&& _Right, index_sequence<_Indices...>) + : _Mybase(static_cast<_Tpl&&>(_Right)._Get_rest()) { + // _Indices... 是编译期生成的 0, 1, 2, ... N-1 索引序列 + // 通过 get<_Indices>(_Right) 逐元素提取并构造 +} + +// 公开构造函数 — 用 make_index_sequence 自动生成索引 +explicit(false) constexpr tuple(_Exact_args_t, _Tpl&& _Right) + : tuple(_Tag{}, _STD forward<_Tpl>(_Right), + make_index_sequence>>{}) {} +``` + +`make_index_sequence` 在编译期生成 `index_sequence<0, 1, ..., N-1>`, 让 tuple 构造可以用 `get<0>` / `get<1>` / ... 依次提取元素。这正是 C++14 放宽 constexpr 后最经典的应用 — 循环不再是运行期概念, 而是通过编译期整数序列 + 参数包展开来完成 + +### std::integer_sequence — C++14 引入的编译期整数载体 + +```cpp +// MSVC STL · msvc-stl/stl/inc/utility (有删节) +template +struct integer_sequence { + static_assert(is_integral_v<_Ty>, + "integer_sequence requires T to be an integral type."); +}; + +template +using index_sequence = integer_sequence; + +template +using make_index_sequence = __make_integer_seq; +``` + +> 小结: `std::make_index_sequence` 和 `std::tuple` 的编译期构造都依赖 C++14 放宽后的 constexpr 环境。没有 loop + branch 的 constexpr, 标准库就只能在编译器内部用黑魔法生成整数序列, 而不能用 C++ 语言自身的表达能力来实现 + +## 三、注意事项 ### C++14 constexpr 仍不支持的操作 @@ -157,7 +201,7 @@ int main() { 把函数标记为 constexpr 并不改变其 ODR 链接属性 (C++17 起 constexpr 函数才隐式 inline), 也不代表所有能 constexpr 的都该 constexpr。如果一个函数几乎只在运行期调用, 加 constexpr 只增加了接口约束, 实际收益很小 -## 三、练习代码 +## 四、练习代码 ### 练习代码主题 @@ -170,7 +214,7 @@ int main() { d2x checker relaxed-constexpr ``` -## 四、其他 +## 五、其他 - [交流讨论](https://forum.d2learn.org/category/20) - [d2mcpp教程仓库](https://github.com/mcpp-community/d2mcpp) diff --git a/dslings/cpp14/01-relaxed-constexpr-0.cpp b/dslings/cpp14/01-relaxed-constexpr-0.cpp new file mode 100644 index 0000000..7d2a855 --- /dev/null +++ b/dslings/cpp14/01-relaxed-constexpr-0.cpp @@ -0,0 +1,68 @@ +// d2mcpp: https://github.com/mcpp-community/d2mcpp +// license: Apache-2.0 +// file: dslings/cpp14/01-relaxed-constexpr-0.cpp +// +// Exercise/练习: cpp14 | 01 - relaxed constexpr | constexpr 循环 +// +// Tips/提示: +// - C++14 constexpr 函数可以使用 for / while 循环 +// - 循环中可以有局部变量和复合语句 +// +// Docs/文档: +// - https://en.cppreference.com/w/cpp/language/constexpr +// - https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp14/01-relaxed-constexpr.md +// +// 练习交流讨论: http://forum.d2learn.org/category/20 +// +// Auto-Checker/自动检测命令: +// +// d2x checker relaxed-constexpr +// + +#include + +// constexpr 阶乘 — C++14 可以用循环 +constexpr int factorial(int n) { + D2X_YOUR_ANSWER result = 1; + for (int i = 1; D2X_YOUR_ANSWER; ++i) { + result *= i; + } + return result; +} + +// constexpr 平方幂 — while 循环版本 +constexpr int power(int base, int exp) { + int result = 1; + int i = 0; + while (D2X_YOUR_ANSWER) { + result *= base; + ++i; + } + return result; +} + +int main() { + + // 0. for 循环 — 编译期阶乘 + constexpr int f5 = factorial(5); + static_assert(f5 == 120, "factorial(5) should be 120"); + d2x_assert_eq(f5, 120); + + constexpr int f0 = factorial(0); + static_assert(f0 == 1, "factorial(0) should be 1"); + + constexpr int f10 = factorial(10); + d2x_assert_eq(f10, 3628800); + + // 1. while 循环 — 编译期幂运算 + constexpr int p2 = power(2, 3); + static_assert(p2 == 8, "power(2,3) should be 8"); + d2x_assert_eq(p2, D2X_YOUR_ANSWER); + + constexpr int p5 = power(5, 2); + d2x_assert_eq(p5, 25); + + D2X_WAIT + + return 0; +} diff --git a/dslings/cpp14/01-relaxed-constexpr-1.cpp b/dslings/cpp14/01-relaxed-constexpr-1.cpp new file mode 100644 index 0000000..4e35be1 --- /dev/null +++ b/dslings/cpp14/01-relaxed-constexpr-1.cpp @@ -0,0 +1,86 @@ +// d2mcpp: https://github.com/mcpp-community/d2mcpp +// license: Apache-2.0 +// file: dslings/cpp14/01-relaxed-constexpr-1.cpp +// +// Exercise/练习: cpp14 | 01 - relaxed constexpr | constexpr 分支与局部变量 +// +// Tips/提示: +// - C++14 constexpr 函数可以使用 if / switch 分支 +// - 可以在 constexpr 中声明和使用多个局部变量 +// +// Docs/文档: +// - https://en.cppreference.com/w/cpp/language/constexpr +// - https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp14/01-relaxed-constexpr.md +// +// 练习交流讨论: http://forum.d2learn.org/category/20 +// +// Auto-Checker/自动检测命令: +// +// d2x checker relaxed-constexpr +// + +#include + +// constexpr 绝对值 — if 分支 +constexpr int my_abs(int x) { + if (D2X_YOUR_ANSWER) { + return -x; + } + return x; +} + +// constexpr 月份天数 — switch 分支 +constexpr int days_in_month(D2X_YOUR_ANSWER month) { + switch (month) { + case 1: case 3: case 5: case 7: case 8: case 10: case 12: + return 31; + case 4: case 6: case 9: case 11: + return 30; + case 2: + return 28; + D2X_YOUR_ANSWER: + return 0; + } +} + +// constexpr 斐波那契 — 多局部变量 + 循环 +constexpr int fib(int n) { + int a = 0, b = D2X_YOUR_ANSWER; + for (int i = 0; i < n; ++i) { + int tmp = a + b; + a = b; + b = tmp; + } + return D2X_YOUR_ANSWER; +} + +int main() { + + // 0. if 分支 + constexpr int a1 = my_abs(-10); + static_assert(a1 == 10, ""); + d2x_assert_eq(a1, 10); + + constexpr int a2 = my_abs(0); + d2x_assert_eq(a2, 0); + + // 1. switch 分支 + constexpr int d7 = days_in_month(7); + static_assert(d7 == 31, "July has 31 days"); + d2x_assert_eq(d7, 31); + + constexpr int d2 = days_in_month(2); + d2x_assert_eq(d2, D2X_YOUR_ANSWER); + + // 2. 多局部变量 + 循环 — fib + constexpr int f10 = fib(10); + static_assert(f10 == 55, "fib(10) should be 55"); + d2x_assert_eq(f10, 55); + + constexpr int f0 = fib(0); + d2x_assert_eq(f0, 0); + + D2X_WAIT + + return 0; +} diff --git a/dslings/en/cpp14/01-relaxed-constexpr-0.cpp b/dslings/en/cpp14/01-relaxed-constexpr-0.cpp new file mode 100644 index 0000000..b392eb3 --- /dev/null +++ b/dslings/en/cpp14/01-relaxed-constexpr-0.cpp @@ -0,0 +1,68 @@ +// d2mcpp: https://github.com/mcpp-community/d2mcpp +// license: Apache-2.0 +// file: dslings/en/cpp14/01-relaxed-constexpr-0.cpp +// +// Exercise: cpp14 | 01 - relaxed constexpr | constexpr with loops +// +// Tips: +// - C++14 constexpr functions can use for / while loops +// - Loops may contain local variables and compound statements +// +// Docs: +// - https://en.cppreference.com/w/cpp/language/constexpr +// - https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp14/01-relaxed-constexpr.md +// +// Discussion Forum: http://forum.d2learn.org/category/20 +// +// Auto-Checker: +// +// d2x checker relaxed-constexpr +// + +#include + +// constexpr factorial — C++14 allows a for loop +constexpr int factorial(int n) { + D2X_YOUR_ANSWER result = 1; + for (int i = 1; D2X_YOUR_ANSWER; ++i) { + result *= i; + } + return result; +} + +// constexpr power — while loop version +constexpr int power(int base, int exp) { + int result = 1; + int i = 0; + while (D2X_YOUR_ANSWER) { + result *= base; + ++i; + } + return result; +} + +int main() { + + // 0. for loop — compile-time factorial + constexpr int f5 = factorial(5); + static_assert(f5 == 120, "factorial(5) should be 120"); + d2x_assert_eq(f5, 120); + + constexpr int f0 = factorial(0); + static_assert(f0 == 1, "factorial(0) should be 1"); + + constexpr int f10 = factorial(10); + d2x_assert_eq(f10, 3628800); + + // 1. while loop — compile-time power + constexpr int p2 = power(2, 3); + static_assert(p2 == 8, "power(2,3) should be 8"); + d2x_assert_eq(p2, D2X_YOUR_ANSWER); + + constexpr int p5 = power(5, 2); + d2x_assert_eq(p5, 25); + + D2X_WAIT + + return 0; +} diff --git a/dslings/en/cpp14/01-relaxed-constexpr-1.cpp b/dslings/en/cpp14/01-relaxed-constexpr-1.cpp new file mode 100644 index 0000000..a5f95f6 --- /dev/null +++ b/dslings/en/cpp14/01-relaxed-constexpr-1.cpp @@ -0,0 +1,86 @@ +// d2mcpp: https://github.com/mcpp-community/d2mcpp +// license: Apache-2.0 +// file: dslings/en/cpp14/01-relaxed-constexpr-1.cpp +// +// Exercise: cpp14 | 01 - relaxed constexpr | constexpr with branches and local variables +// +// Tips: +// - C++14 constexpr functions can use if / switch branches +// - Multiple local variables can be declared and used in constexpr +// +// Docs: +// - https://en.cppreference.com/w/cpp/language/constexpr +// - https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp14/01-relaxed-constexpr.md +// +// Discussion Forum: http://forum.d2learn.org/category/20 +// +// Auto-Checker: +// +// d2x checker relaxed-constexpr +// + +#include + +// constexpr absolute value — if branch +constexpr int my_abs(int x) { + if (D2X_YOUR_ANSWER) { + return -x; + } + return x; +} + +// constexpr days in month — switch branch +constexpr int days_in_month(D2X_YOUR_ANSWER month) { + switch (month) { + case 1: case 3: case 5: case 7: case 8: case 10: case 12: + return 31; + case 4: case 6: case 9: case 11: + return 30; + case 2: + return 28; + D2X_YOUR_ANSWER: + return 0; + } +} + +// constexpr fibonacci — multiple local variables + loop +constexpr int fib(int n) { + int a = 0, b = D2X_YOUR_ANSWER; + for (int i = 0; i < n; ++i) { + int tmp = a + b; + a = b; + b = tmp; + } + return D2X_YOUR_ANSWER; +} + +int main() { + + // 0. if branch + constexpr int a1 = my_abs(-10); + static_assert(a1 == 10, ""); + d2x_assert_eq(a1, 10); + + constexpr int a2 = my_abs(0); + d2x_assert_eq(a2, 0); + + // 1. switch branch + constexpr int d7 = days_in_month(7); + static_assert(d7 == 31, "July has 31 days"); + d2x_assert_eq(d7, 31); + + constexpr int d2 = days_in_month(2); + d2x_assert_eq(d2, D2X_YOUR_ANSWER); + + // 2. multiple local variables + loop — fib + constexpr int f10 = fib(10); + static_assert(f10 == 55, "fib(10) should be 55"); + d2x_assert_eq(f10, 55); + + constexpr int f0 = fib(0); + d2x_assert_eq(f0, 0); + + D2X_WAIT + + return 0; +} diff --git a/solutions/cpp14/01-relaxed-constexpr-0.cpp b/solutions/cpp14/01-relaxed-constexpr-0.cpp new file mode 100644 index 0000000..747b42e --- /dev/null +++ b/solutions/cpp14/01-relaxed-constexpr-0.cpp @@ -0,0 +1,49 @@ +// d2mcpp: https://github.com/mcpp-community/d2mcpp +// license: Apache-2.0 +// reference solution for: dslings/cpp14/01-relaxed-constexpr-0.cpp +// +// 用途: 仅给 CI 与维护者参考使用,不是教程入口。 +// 教程练习入口: dslings/cpp14/01-relaxed-constexpr-0.cpp +// + +#include + +constexpr int factorial(int n) { + int result = 1; + for (int i = 1; i <= n; ++i) { + result *= i; + } + return result; +} + +constexpr int power(int base, int exp) { + int result = 1; + int i = 0; + while (i < exp) { + result *= base; + ++i; + } + return result; +} + +int main() { + + constexpr int f5 = factorial(5); + static_assert(f5 == 120, "factorial(5) should be 120"); + d2x_assert_eq(f5, 120); + + constexpr int f0 = factorial(0); + static_assert(f0 == 1, "factorial(0) should be 1"); + + constexpr int f10 = factorial(10); + d2x_assert_eq(f10, 3628800); + + constexpr int p2 = power(2, 3); + static_assert(p2 == 8, "power(2,3) should be 8"); + d2x_assert_eq(p2, 8); + + constexpr int p5 = power(5, 2); + d2x_assert_eq(p5, 25); + + return 0; +} diff --git a/solutions/cpp14/01-relaxed-constexpr-1.cpp b/solutions/cpp14/01-relaxed-constexpr-1.cpp new file mode 100644 index 0000000..883e93f --- /dev/null +++ b/solutions/cpp14/01-relaxed-constexpr-1.cpp @@ -0,0 +1,65 @@ +// d2mcpp: https://github.com/mcpp-community/d2mcpp +// license: Apache-2.0 +// reference solution for: dslings/cpp14/01-relaxed-constexpr-1.cpp +// +// 用途: 仅给 CI 与维护者参考使用,不是教程入口。 +// 教程练习入口: dslings/cpp14/01-relaxed-constexpr-1.cpp +// + +#include + +constexpr int my_abs(int x) { + if (x < 0) { + return -x; + } + return x; +} + +constexpr int days_in_month(int month) { + switch (month) { + case 1: case 3: case 5: case 7: case 8: case 10: case 12: + return 31; + case 4: case 6: case 9: case 11: + return 30; + case 2: + return 28; + default: + return 0; + } +} + +constexpr int fib(int n) { + int a = 0, b = 1; + for (int i = 0; i < n; ++i) { + int tmp = a + b; + a = b; + b = tmp; + } + return a; +} + +int main() { + + constexpr int a1 = my_abs(-10); + static_assert(a1 == 10, ""); + d2x_assert_eq(a1, 10); + + constexpr int a2 = my_abs(0); + d2x_assert_eq(a2, 0); + + constexpr int d7 = days_in_month(7); + static_assert(d7 == 31, "July has 31 days"); + d2x_assert_eq(d7, 31); + + constexpr int d2 = days_in_month(2); + d2x_assert_eq(d2, 28); + + constexpr int f10 = fib(10); + static_assert(f10 == 55, "fib(10) should be 55"); + d2x_assert_eq(f10, 55); + + constexpr int f0 = fib(0); + d2x_assert_eq(f0, 0); + + return 0; +}