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..b606dd7
--- /dev/null
+++ b/book/en/src/cpp14/01-relaxed-constexpr.md
@@ -0,0 +1,222 @@
+
+
+ 🌎 [中文] | [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. 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
+
+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
+
+## IV. 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
+```
+
+## V. 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..698f2a3
--- /dev/null
+++ b/book/src/cpp14/01-relaxed-constexpr.md
@@ -0,0 +1,222 @@
+
+
+ 🌎 [中文] | [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, "");
+```
+
+## 二、真实案例 - 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 仍不支持的操作
+
+以下操作在 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/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/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/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/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/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;
+}
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")