From c38700464181283b16b782e6a4e3c37e28f0b08f Mon Sep 17 00:00:00 2001
From: li-zhou <2181719471@qq.com>
Date: Mon, 15 Jun 2026 20:21:16 +0800
Subject: [PATCH 1/4] docs(cpp14): add 00-generic-lambdas book chapter and
build wiring
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add the first C++14 chapter covering generic lambdas — lambda parameters
using auto, which the compiler expands into a functor with a templated
operator().
Book structure (zh + en):
- 一/II: Basic usage — identity, multi-param, STL algorithms, captures,
returning lambda (factory pattern)
- 二/II: Notes — closure type uniqueness, perfect forwarding, non-variadic
- 三/III: Exercise topics and d2x checker command
- 四/IV: External resources
Build wiring:
- register cpp14 in dslings/xmake.lua, dslings/en/xmake.lua,
solutions/xmake.lua
- add cpp14 entry to zh/en SUMMARY.md and book/README.md
- remove stale dslings/cpp14/README.md TODO placeholder
Files: book/src/cpp14/, book/en/src/cpp14/, book/src/SUMMARY.md,
book/en/src/SUMMARY.md, book/README.md,
dslings/xmake.lua, dslings/en/xmake.lua, solutions/xmake.lua,
dslings/cpp14/README.md (deleted)
---
book/README.md | 1 +
book/en/src/SUMMARY.md | 2 +
book/en/src/cpp14/00-generic-lambdas.md | 166 ++++++++++++++++++++++++
book/src/SUMMARY.md | 2 +
book/src/cpp14/00-generic-lambdas.md | 166 ++++++++++++++++++++++++
dslings/cpp14/README.md | 1 -
dslings/en/xmake.lua | 1 +
dslings/xmake.lua | 1 +
solutions/xmake.lua | 1 +
9 files changed, 340 insertions(+), 1 deletion(-)
create mode 100644 book/en/src/cpp14/00-generic-lambdas.md
create mode 100644 book/src/cpp14/00-generic-lambdas.md
delete mode 100644 dslings/cpp14/README.md
diff --git a/book/README.md b/book/README.md
index 11434e5..0eab295 100644
--- a/book/README.md
+++ b/book/README.md
@@ -1,3 +1,4 @@
**现代C++标准(cppref)**
- C++11: [中](https://zh.cppreference.com/w/cpp/11) / [En](https://en.cppreference.com/w/cpp/11)
+ - C++14: [中](https://zh.cppreference.com/w/cpp/14) / [En](https://en.cppreference.com/w/cpp/14)
diff --git a/book/en/src/SUMMARY.md b/book/en/src/SUMMARY.md
index d3754ca..b2008be 100644
--- a/book/en/src/SUMMARY.md
+++ b/book/en/src/SUMMARY.md
@@ -30,6 +30,8 @@
# C++14 Core Language Features
+- [Generic Lambdas](./cpp14/00-generic-lambdas.md)
+
# Additional Resources
- [Changelog](changelog.md)
diff --git a/book/en/src/cpp14/00-generic-lambdas.md b/book/en/src/cpp14/00-generic-lambdas.md
new file mode 100644
index 0000000..85979ed
--- /dev/null
+++ b/book/en/src/cpp14/00-generic-lambdas.md
@@ -0,0 +1,166 @@
+
+
+ 🌎 [中文] | [English]
+
+
+[中文]: ../../cpp14/00-generic-lambdas.html
+[English]: ./00-generic-lambdas.html
+
+# Generic Lambdas
+
+C++14 allows lambda parameters to use `auto`, turning the lambda's `operator()` into an implicit function template — a single lambda can accept arguments of different types
+
+| Book | Video | Code | X |
+| --- | --- | --- | --- |
+| [cppreference-lambda](https://en.cppreference.com/w/cpp/language/lambda) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp14/00-generic-lambdas.md) | [Video Explanation]() | [Exercise Code](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp14/00-generic-lambdas-0.cpp) | |
+
+
+**Why introduced?**
+
+- In C++11, lambda parameter types must be explicitly specified — the same lambda cannot be reused for different argument types because `operator()` is a plain member function, not a template
+- Many lambdas express type-independent logic (e.g. `[](auto a, auto b) { return a < b; }` works for `int`, `double`, `string`), but C++11 required writing a separate lambda for each type
+- C++14 allows `auto` in lambda parameters; the compiler generates an implicit template for `operator()`, essentially bringing function templates into the lambda world
+
+**How does it work?**
+
+The compiler expands a generic lambda into a functor class with a **templated `operator()`**. For example, `[](auto a, auto b) { return a + b; }` is internally equivalent to:
+
+```cpp
+struct __lambda {
+ template
+ auto operator()(T1 a, T2 b) const {
+ return a + b;
+ }
+};
+```
+
+## I. Basic Usage and Scenarios
+
+### Simple Generic Lambda
+
+> Declare lambda parameters with auto; the compiler generates operator() instances based on the argument types at the call site
+
+```cpp
+auto identity = [](auto x) {
+ return x;
+};
+
+int i = identity(42); // x deduced as int
+double d = identity(3.14); // x deduced as double
+```
+
+### Multi-Parameter Generic Lambda
+
+```cpp
+auto add = [](auto a, auto b) {
+ return a + b;
+};
+
+add(1, 2); // int + int
+add(1.5, 2.5); // double + double
+add(std::string("hello "), std::string("world")); // string + string
+```
+
+Each parameter's type is deduced independently; `T1` and `T2` can differ:
+
+```cpp
+auto multiply = [](auto a, auto b) {
+ return a * b;
+};
+
+multiply(2, 3.5); // int * double → double
+```
+
+### Generic Lambda + STL Algorithms
+
+The most common use case — avoid writing identical logic for every container element type:
+
+```cpp
+std::vector v1 = {5, 1, 4, 2, 8};
+std::vector v2 = {3.1, 2.7, 8.5, 1.9};
+
+// C++11: write separate lambdas for int and double
+std::sort(v1.begin(), v1.end(), [](int a, int b) { return a > b; });
+std::sort(v2.begin(), v2.end(), [](double a, double b) { return a > b; });
+
+// C++14: a single generic lambda handles both
+auto gt = [](auto a, auto b) { return a > b; };
+std::sort(v1.begin(), v1.end(), gt);
+std::sort(v2.begin(), v2.end(), gt);
+```
+
+### Generic Lambda with Captures
+
+Captured variables keep their concrete types; only parameters use `auto`:
+
+```cpp
+int threshold = 10;
+auto above = [threshold](auto x) {
+ return x > threshold; // threshold is int, x is generic
+};
+
+above(20); // x = int
+above(3.5); // x = double
+```
+
+### Generic Lambda Returning Lambda
+
+A generic lambda can return a new lambda, creating a function factory:
+
+```cpp
+auto make_adder = [](auto n) {
+ return [n](auto x) { return x + n; }; // C++14 supports this
+};
+
+auto add5 = make_adder(5);
+add5(10); // 15
+add5(3.14); // 8.14
+```
+
+## II. Notes
+
+### A Generic Lambda Is a Class with a Templated operator()
+
+Each generic lambda expression produces a distinct closure type. Even two identical-looking generic lambdas have different types — the same rule as regular lambdas, but the `operator()` is a template, so the same type can accept different argument types
+
+```cpp
+auto f = [](auto x) { return x; };
+auto g = [](auto x) { return x; };
+// f and g have different types; cannot be assigned to each other
+```
+
+### Generic Parameters and Perfect Forwarding
+
+Generic lambda parameter deduction strips references and const by default. Use `auto&&` with `std::forward` to preserve them:
+
+```cpp
+auto forwarder = [](auto&& x) -> decltype(auto) {
+ return std::forward(x);
+};
+```
+
+This pattern is common with generic lambdas and is a typical use case for `decltype(auto)` (another C++14 feature)
+
+### Generic Lambdas Are Not Variadic
+
+The parameter count is still fixed — `[](auto a, auto b)` accepts exactly two arguments. For variadic parameters, you still need variadic templates (C++20 later added support for `...` parameter packs in lambdas)
+
+## III. Exercise Code
+
+### Exercise Code Topics
+
+- 0 - [Basic Generic Lambda — auto parameters and type deduction](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp14/00-generic-lambdas-0.cpp)
+- 1 - [Generic Lambda with STL Algorithms — sort, find, factory function](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/en/cpp14/00-generic-lambdas-1.cpp)
+
+### Exercise Auto-Checker Command
+
+```
+d2x checker generic-lambdas
+```
+
+## 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 040e15b..7efe83a 100644
--- a/book/src/SUMMARY.md
+++ b/book/src/SUMMARY.md
@@ -30,6 +30,8 @@
# C++14核心语言特性
+- [泛型 lambda - generic lambdas](./cpp14/00-generic-lambdas.md)
+
# 其他
- [更新日志](changelog.md)
diff --git a/book/src/cpp14/00-generic-lambdas.md b/book/src/cpp14/00-generic-lambdas.md
new file mode 100644
index 0000000..d260120
--- /dev/null
+++ b/book/src/cpp14/00-generic-lambdas.md
@@ -0,0 +1,166 @@
+
+
+ 🌎 [中文] | [English]
+
+
+[中文]: ./00-generic-lambdas.html
+[English]: ../en/cpp14/00-generic-lambdas.html
+
+# 泛型 lambda - generic lambdas
+
+泛型 lambda 是 C++14 在 lambda 表达式上引入的一项重要增强, 允许 lambda 的参数使用 `auto` 类型推导, 使得一个 lambda 表达式可以像函数模板一样处理不同类型的参数
+
+| Book | Video | Code | X |
+| --- | --- | --- | --- |
+| [cppreference-lambda](https://en.cppreference.com/w/cpp/language/lambda) / [markdown](https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp14/00-generic-lambdas.md) | [视频解读]() | [练习代码](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp14/00-generic-lambdas-0.cpp) | |
+
+
+**为什么引入?**
+
+- C++11 的 lambda 参数类型必须显式指定, 同一个 lambda 无法复用于不同类型的参数 — 本质上 lambda 的 `operator()` 是一个普通成员函数, 不能是模板
+- 在实际编码中, 很多 lambda 的逻辑与类型无关 (例如 `[](int a, int b) { return a < b; }` 中的比较逻辑对 `int` / `double` / `string` 都适用), 但 C++11 要求为每种类型写一份
+- C++14 允许 lambda 参数使用 `auto`, 编译器会为 `operator()` 生成一个隐式的模板, 每种参数类型实例化一份 — 相当于把"函数模板"带到了 lambda 世界里
+
+**泛型 lambda 是如何实现的?**
+
+编译器将泛型 lambda 展开为一个带有**模板化 `operator()`** 的仿函数类。例如 `[](auto a, auto b) { return a + b; }` 在内部等价于:
+
+```cpp
+struct __lambda {
+ template
+ auto operator()(T1 a, T2 b) const {
+ return a + b;
+ }
+};
+```
+
+## 一、基础用法和场景
+
+### 简单泛型 lambda
+
+> lambda 参数用 auto 声明, 编译器根据调用时的实参类型生成对应的 operator() 实例
+
+```cpp
+auto identity = [](auto x) {
+ return x;
+};
+
+int i = identity(42); // x 推导为 int
+double d = identity(3.14); // x 推导为 double
+```
+
+### 多参数泛型 lambda
+
+```cpp
+auto add = [](auto a, auto b) {
+ return a + b;
+};
+
+add(1, 2); // int + int
+add(1.5, 2.5); // double + double
+add(std::string("hello "), std::string("world")); // string + string
+```
+
+每个参数的类型是独立推导的, `T1` 和 `T2` 可以不同:
+
+```cpp
+auto multiply = [](auto a, auto b) {
+ return a * b;
+};
+
+multiply(2, 3.5); // int * double → double
+```
+
+### 泛型 lambda + STL 算法
+
+泛型 lambda 最常见的应用场景是配合 STL 算法, 避免为每种容器元素类型重复编写相同逻辑的比较/判据:
+
+```cpp
+std::vector v1 = {5, 1, 4, 2, 8};
+std::vector v2 = {3.1, 2.7, 8.5, 1.9};
+
+// C++11: 需要为 int 和 double 分别写 lambda
+std::sort(v1.begin(), v1.end(), [](int a, int b) { return a > b; });
+std::sort(v2.begin(), v2.end(), [](double a, double b) { return a > b; });
+
+// C++14: 同一个泛型 lambda 搞定
+auto gt = [](auto a, auto b) { return a > b; };
+std::sort(v1.begin(), v1.end(), gt);
+std::sort(v2.begin(), v2.end(), gt);
+```
+
+### 带捕获的泛型 lambda
+
+捕获的变量类型不变, 只有参数用 `auto`:
+
+```cpp
+int threshold = 10;
+auto above = [threshold](auto x) {
+ return x > threshold; // threshold 捕获为 int, x 是泛型参数
+};
+
+above(20); // x = int
+above(3.5); // x = double
+```
+
+### 泛型 lambda 返回 lambda
+
+泛型 lambda 可以返回一个新 lambda, 实现类似"函数工厂"的效果:
+
+```cpp
+auto make_adder = [](auto n) {
+ return [n](auto x) { return x + n; }; // C++14 支持, 返回类型自动推导
+};
+
+auto add5 = make_adder(5);
+add5(10); // 15
+add5(3.14); // 8.14
+```
+
+## 二、注意事项
+
+### 泛型 lambda 是一个有模板 operator() 的类
+
+每个泛型 lambda 表达式产生一个独立的闭包类型。即使是写法完全相同的两个泛型 lambda, 它们的类型也不同 — 这和普通 lambda 的规则一样, 但泛型 lambda 的 `operator()` 是模板, 所以同一类型可以接受不同参数类型
+
+```cpp
+auto f = [](auto x) { return x; };
+auto g = [](auto x) { return x; };
+// f 和 g 的类型不同, 不能互相赋值
+```
+
+### 泛型参数和完美转发
+
+泛型 lambda 的参数推导默认剥离引用和 const, 需要完整保留时用 `auto&&` 配合 `std::forward`:
+
+```cpp
+auto forwarder = [](auto&& x) -> decltype(auto) {
+ return std::forward(x);
+};
+```
+
+这种写法在泛型 lambda 里很常见, 也是 `decltype(auto)` (C++14 的另一特性) 的典型使用场景
+
+### 泛型 lambda 不是 variadic
+
+泛型 lambda 的参数个数仍然是固定的 — `[](auto a, auto b)` 接受恰好两个参数。如果要变参, 仍然需要可变参数模板 (C++20 后才支持 lambda 中使用 `...` 参数包)
+
+## 三、练习代码
+
+### 练习代码主题
+
+- 0 - [泛型 lambda 基础 — auto 参数与类型推导](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp14/00-generic-lambdas-0.cpp)
+- 1 - [泛型 lambda 与 STL 算法 — 排序、查找、函数工厂](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp14/00-generic-lambdas-1.cpp)
+
+### 练习代码自动检测命令
+
+```
+d2x checker generic-lambdas
+```
+
+## 四、其他
+
+- [交流讨论](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/README.md b/dslings/cpp14/README.md
deleted file mode 100644
index f87f5c1..0000000
--- a/dslings/cpp14/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# TODO
\ No newline at end of file
diff --git a/dslings/en/xmake.lua b/dslings/en/xmake.lua
index b1edd93..7678d9a 100644
--- a/dslings/en/xmake.lua
+++ b/dslings/en/xmake.lua
@@ -3,3 +3,4 @@ target("00-0-hello-mcpp")
add_files("hello-mcpp.cpp")
includes("cpp11")
+includes("cpp14")
diff --git a/dslings/xmake.lua b/dslings/xmake.lua
index bb8e9af..32c5a95 100644
--- a/dslings/xmake.lua
+++ b/dslings/xmake.lua
@@ -17,6 +17,7 @@ if lang == "zh" then
add_files("hello-mcpp.cpp")
includes("cpp11")
+ includes("cpp14")
else
includes("en")
end
diff --git a/solutions/xmake.lua b/solutions/xmake.lua
index f8ed5ab..c1b845e 100644
--- a/solutions/xmake.lua
+++ b/solutions/xmake.lua
@@ -8,3 +8,4 @@
-- contributors, not the compiler, so we keep a single zh-style copy.
includes("cpp11/xmake.lua")
+includes("cpp14/xmake.lua")
From 3fa0d39e8fa371c7a45601544ed1b8fb7a68bc98 Mon Sep 17 00:00:00 2001
From: li-zhou <2181719471@qq.com>
Date: Mon, 15 Jun 2026 20:31:46 +0800
Subject: [PATCH 2/4] feat(cpp14): add 00-generic-lambdas exercises and
solutions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Exercise progression:
0. Basic generic lambda — auto parameter identity/comparison/type-size
exercises. Learner fills auto param type, return expression, and
sizeof argument. 4 D2X_YOUR_ANSWER.
1. Generic lambda with STL algorithms — same lambda reused across
vector and vector for sort/find_if, plus a factory
pattern returning a lambda. 5 D2X_YOUR_ANSWER.
Design rationale:
Generic lambdas have three layers worth teaching independently:
(1) syntax — auto in lambda parameters generates a templated operator();
(2) reuse — a single lambda serves multiple container types, the
primary motivation for the feature;
(3) interaction — generic lambda returns + captures work naturally
without extra syntax.
ex 0 isolates layer (1). identity forces the learner to write auto
in a parameter position. greater verifies the return expression is
type-checked per instantiation. get_type_size confirms that sizeof
on a generic parameter works correctly, reinforcing the "compiler
stamps out per-type copies" mental model. Everything is self-contained
and runnable without headers beyond .
ex 1 layers (2) and (3) on top. The desc lambda applied to both
vector and vector makes the payoff tangible — contrast
with the C++11 approach of duplicating the comparator. The find_if
exercise adds a capture without complicating the generic parameter.
The make_multiplier factory previews generic-lambda-returning-lambda,
which is a pattern that only becomes practical with C++14 return type
deduction.
We deliberately limited this chapter to 2 exercises. A third exercise
covering perfect forwarding + auto&& + decltype(auto) is better placed
in the decltype(auto) chapter where the forwarding semantics are the
primary topic, not a side note.
Files: dslings/cpp14/00-generic-lambdas-{0,1}.cpp (zh),
dslings/en/cpp14/00-generic-lambdas-{0,1}.cpp (en),
dslings/cpp14/xmake.lua, dslings/en/cpp14/xmake.lua,
solutions/cpp14/00-generic-lambdas-{0,1}.cpp,
solutions/cpp14/xmake.lua
---
dslings/cpp14/00-generic-lambdas-0.cpp | 56 +++++++++++++++++++
dslings/cpp14/00-generic-lambdas-1.cpp | 67 ++++++++++++++++++++++
dslings/cpp14/xmake.lua | 11 ++++
dslings/en/cpp14/00-generic-lambdas-0.cpp | 57 +++++++++++++++++++
dslings/en/cpp14/00-generic-lambdas-1.cpp | 68 +++++++++++++++++++++++
dslings/en/cpp14/xmake.lua | 11 ++++
solutions/cpp14/00-generic-lambdas-0.cpp | 41 ++++++++++++++
solutions/cpp14/00-generic-lambdas-1.cpp | 52 +++++++++++++++++
solutions/cpp14/xmake.lua | 11 ++++
9 files changed, 374 insertions(+)
create mode 100644 dslings/cpp14/00-generic-lambdas-0.cpp
create mode 100644 dslings/cpp14/00-generic-lambdas-1.cpp
create mode 100644 dslings/cpp14/xmake.lua
create mode 100644 dslings/en/cpp14/00-generic-lambdas-0.cpp
create mode 100644 dslings/en/cpp14/00-generic-lambdas-1.cpp
create mode 100644 dslings/en/cpp14/xmake.lua
create mode 100644 solutions/cpp14/00-generic-lambdas-0.cpp
create mode 100644 solutions/cpp14/00-generic-lambdas-1.cpp
create mode 100644 solutions/cpp14/xmake.lua
diff --git a/dslings/cpp14/00-generic-lambdas-0.cpp b/dslings/cpp14/00-generic-lambdas-0.cpp
new file mode 100644
index 0000000..31ccdd3
--- /dev/null
+++ b/dslings/cpp14/00-generic-lambdas-0.cpp
@@ -0,0 +1,56 @@
+// d2mcpp: https://github.com/mcpp-community/d2mcpp
+// license: Apache-2.0
+// file: dslings/cpp14/00-generic-lambdas-0.cpp
+//
+// Exercise/练习: cpp14 | 00 - generic lambdas | 泛型 lambda
+//
+// Tips/提示:
+// - lambda 参数使用 auto, 编译器为 operator() 生成隐式模板
+// - 同一个泛型 lambda 可以接受不同类型的参数
+//
+// Docs/文档:
+// - https://en.cppreference.com/w/cpp/language/lambda
+// - https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp14/00-generic-lambdas.md
+//
+// 练习交流讨论: http://forum.d2learn.org/category/20
+//
+// Auto-Checker/自动检测命令:
+//
+// d2x checker generic-lambdas
+//
+
+#include
+#include
+
+int main() {
+
+ // 0. 简单泛型 lambda — identity
+ auto identity = [](D2X_YOUR_ANSWER x) {
+ return x;
+ };
+
+ d2x_assert_eq(identity(42), 42);
+ d2x_assert(identity(std::string("hello")) == "hello");
+ d2x_assert_eq(identity(3.14), D2X_YOUR_ANSWER);
+
+ // 1. 泛型 lambda 做比较
+ auto greater = [](auto a, auto b) {
+ return D2X_YOUR_ANSWER;
+ };
+
+ d2x_assert(greater(5, 3));
+ d2x_assert(greater(2.5, 1.2));
+ d2x_assert(greater(std::string("z"), std::string("a")));
+
+ // 2. 推导类型确认
+ auto get_type_size = [](auto x) {
+ return sizeof(D2X_YOUR_ANSWER);
+ };
+
+ d2x_assert_eq(get_type_size(42), sizeof(int));
+ d2x_assert_eq(get_type_size('c'), sizeof(char));
+
+ D2X_WAIT
+
+ return 0;
+}
diff --git a/dslings/cpp14/00-generic-lambdas-1.cpp b/dslings/cpp14/00-generic-lambdas-1.cpp
new file mode 100644
index 0000000..e3f0c5b
--- /dev/null
+++ b/dslings/cpp14/00-generic-lambdas-1.cpp
@@ -0,0 +1,67 @@
+// d2mcpp: https://github.com/mcpp-community/d2mcpp
+// license: Apache-2.0
+// file: dslings/cpp14/00-generic-lambdas-1.cpp
+//
+// Exercise/练习: cpp14 | 00 - generic lambdas | 泛型 lambda 与 STL 算法
+//
+// Tips/提示:
+// - 泛型 lambda 可复用于不同元素类型的容器, 同一个 lambda 传给多种 STL 算法
+// - 捕获的变量类型不变, 只有参数用 auto
+//
+// Docs/文档:
+// - https://en.cppreference.com/w/cpp/language/lambda
+// - https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp14/00-generic-lambdas.md
+//
+// 练习交流讨论: http://forum.d2learn.org/category/20
+//
+// Auto-Checker/自动检测命令:
+//
+// d2x checker generic-lambdas
+//
+
+#include
+#include
+#include
+
+int main() {
+
+ // 0. 同一个泛型 lambda 用于不同元素类型的容器排序
+ std::vector v1 = {5, 1, 4, 2, 8};
+ std::vector v2 = {3.1, 2.7, 8.5, 1.9};
+
+ auto desc = [](D2X_YOUR_ANSWER a, D2X_YOUR_ANSWER b) {
+ return a > b;
+ };
+
+ std::sort(v1.begin(), v1.end(), desc);
+ d2x_assert_eq(v1[0], 8);
+ d2x_assert_eq(v1[4], 1);
+
+ std::sort(v2.begin(), v2.end(), desc);
+ d2x_assert_eq(v2[0], D2X_YOUR_ANSWER);
+
+ // 1. 带捕获的泛型 lambda — find_if
+ int threshold = 3;
+ auto above = [threshold](auto x) {
+ return x > threshold;
+ };
+
+ auto it1 = std::find_if(v1.begin(), v1.end(), above);
+ d2x_assert(*it1 == D2X_YOUR_ANSWER);
+
+ auto it2 = std::find_if(v2.begin(), v2.end(), above);
+ d2x_assert(*it2 == 8.5);
+
+ // 2. 泛型 lambda 返回 lambda — 函数工厂
+ auto make_multiplier = [](auto factor) {
+ return [factor](auto x) { return x * D2X_YOUR_ANSWER; };
+ };
+
+ auto times2 = make_multiplier(2);
+ d2x_assert_eq(times2(10), 20);
+ d2x_assert_eq(times2(0.5), 1.0);
+
+ D2X_WAIT
+
+ return 0;
+}
diff --git a/dslings/cpp14/xmake.lua b/dslings/cpp14/xmake.lua
new file mode 100644
index 0000000..8a21cbf
--- /dev/null
+++ b/dslings/cpp14/xmake.lua
@@ -0,0 +1,11 @@
+set_languages("cxx14")
+
+-- target: cpp14-00-generic-lambdas
+
+target("cpp14-00-generic-lambdas-0")
+ set_kind("binary")
+ add_files("00-generic-lambdas-0.cpp")
+
+target("cpp14-00-generic-lambdas-1")
+ set_kind("binary")
+ add_files("00-generic-lambdas-1.cpp")
diff --git a/dslings/en/cpp14/00-generic-lambdas-0.cpp b/dslings/en/cpp14/00-generic-lambdas-0.cpp
new file mode 100644
index 0000000..3d2c16e
--- /dev/null
+++ b/dslings/en/cpp14/00-generic-lambdas-0.cpp
@@ -0,0 +1,57 @@
+// d2mcpp: https://github.com/mcpp-community/d2mcpp
+// license: Apache-2.0
+// file: dslings/en/cpp14/00-generic-lambdas-0.cpp
+//
+// Exercise: cpp14 | 00 - generic lambdas | basic generic lambda
+//
+// Tips:
+// - Use auto in lambda parameters; the compiler generates an implicit
+// template for operator()
+// - The same generic lambda can accept arguments of different types
+//
+// Docs:
+// - https://en.cppreference.com/w/cpp/language/lambda
+// - https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp14/00-generic-lambdas.md
+//
+// Discussion Forum: http://forum.d2learn.org/category/20
+//
+// Auto-Checker:
+//
+// d2x checker generic-lambdas
+//
+
+#include
+#include
+
+int main() {
+
+ // 0. Simple generic lambda — identity
+ auto identity = [](D2X_YOUR_ANSWER x) {
+ return x;
+ };
+
+ d2x_assert_eq(identity(42), 42);
+ d2x_assert(identity(std::string("hello")) == "hello");
+ d2x_assert_eq(identity(3.14), D2X_YOUR_ANSWER);
+
+ // 1. Generic lambda as comparator
+ auto greater = [](auto a, auto b) {
+ return D2X_YOUR_ANSWER;
+ };
+
+ d2x_assert(greater(5, 3));
+ d2x_assert(greater(2.5, 1.2));
+ d2x_assert(greater(std::string("z"), std::string("a")));
+
+ // 2. Verify deduced types
+ auto get_type_size = [](auto x) {
+ return sizeof(D2X_YOUR_ANSWER);
+ };
+
+ d2x_assert_eq(get_type_size(42), sizeof(int));
+ d2x_assert_eq(get_type_size('c'), sizeof(char));
+
+ D2X_WAIT
+
+ return 0;
+}
diff --git a/dslings/en/cpp14/00-generic-lambdas-1.cpp b/dslings/en/cpp14/00-generic-lambdas-1.cpp
new file mode 100644
index 0000000..d23df54
--- /dev/null
+++ b/dslings/en/cpp14/00-generic-lambdas-1.cpp
@@ -0,0 +1,68 @@
+// d2mcpp: https://github.com/mcpp-community/d2mcpp
+// license: Apache-2.0
+// file: dslings/en/cpp14/00-generic-lambdas-1.cpp
+//
+// Exercise: cpp14 | 00 - generic lambdas | generic lambda with STL algorithms
+//
+// Tips:
+// - A single generic lambda can be reused with containers of different
+// element types
+// - Captured variables retain their concrete types; only parameters use auto
+//
+// Docs:
+// - https://en.cppreference.com/w/cpp/language/lambda
+// - https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp14/00-generic-lambdas.md
+//
+// Discussion Forum: http://forum.d2learn.org/category/20
+//
+// Auto-Checker:
+//
+// d2x checker generic-lambdas
+//
+
+#include
+#include
+#include
+
+int main() {
+
+ // 0. Same generic lambda used to sort containers of different element types
+ std::vector v1 = {5, 1, 4, 2, 8};
+ std::vector v2 = {3.1, 2.7, 8.5, 1.9};
+
+ auto desc = [](D2X_YOUR_ANSWER a, D2X_YOUR_ANSWER b) {
+ return a > b;
+ };
+
+ std::sort(v1.begin(), v1.end(), desc);
+ d2x_assert_eq(v1[0], 8);
+ d2x_assert_eq(v1[4], 1);
+
+ std::sort(v2.begin(), v2.end(), desc);
+ d2x_assert_eq(v2[0], D2X_YOUR_ANSWER);
+
+ // 1. Generic lambda with capture — find_if
+ int threshold = 3;
+ auto above = [threshold](auto x) {
+ return x > threshold;
+ };
+
+ auto it1 = std::find_if(v1.begin(), v1.end(), above);
+ d2x_assert(*it1 == D2X_YOUR_ANSWER);
+
+ auto it2 = std::find_if(v2.begin(), v2.end(), above);
+ d2x_assert(*it2 == 8.5);
+
+ // 2. Generic lambda returning lambda — factory function
+ auto make_multiplier = [](auto factor) {
+ return [factor](auto x) { return x * D2X_YOUR_ANSWER; };
+ };
+
+ auto times2 = make_multiplier(2);
+ d2x_assert_eq(times2(10), 20);
+ d2x_assert_eq(times2(0.5), 1.0);
+
+ D2X_WAIT
+
+ return 0;
+}
diff --git a/dslings/en/cpp14/xmake.lua b/dslings/en/cpp14/xmake.lua
new file mode 100644
index 0000000..8a21cbf
--- /dev/null
+++ b/dslings/en/cpp14/xmake.lua
@@ -0,0 +1,11 @@
+set_languages("cxx14")
+
+-- target: cpp14-00-generic-lambdas
+
+target("cpp14-00-generic-lambdas-0")
+ set_kind("binary")
+ add_files("00-generic-lambdas-0.cpp")
+
+target("cpp14-00-generic-lambdas-1")
+ set_kind("binary")
+ add_files("00-generic-lambdas-1.cpp")
diff --git a/solutions/cpp14/00-generic-lambdas-0.cpp b/solutions/cpp14/00-generic-lambdas-0.cpp
new file mode 100644
index 0000000..473711b
--- /dev/null
+++ b/solutions/cpp14/00-generic-lambdas-0.cpp
@@ -0,0 +1,41 @@
+// d2mcpp: https://github.com/mcpp-community/d2mcpp
+// license: Apache-2.0
+// reference solution for: dslings/cpp14/00-generic-lambdas-0.cpp
+//
+// 用途: 仅给 CI 与维护者参考使用,不是教程入口。
+// 教程练习入口: dslings/cpp14/00-generic-lambdas-0.cpp
+//
+
+#include
+#include
+
+int main() {
+
+ // 0. 简单泛型 lambda — identity
+ auto identity = [](auto x) {
+ return x;
+ };
+
+ d2x_assert_eq(identity(42), 42);
+ d2x_assert(identity(std::string("hello")) == "hello");
+ d2x_assert_eq(identity(3.14), 3.14);
+
+ // 1. 泛型 lambda 做比较
+ auto greater = [](auto a, auto b) {
+ return a > b;
+ };
+
+ d2x_assert(greater(5, 3));
+ d2x_assert(greater(2.5, 1.2));
+ d2x_assert(greater(std::string("z"), std::string("a")));
+
+ // 2. 推导类型确认
+ auto get_type_size = [](auto x) {
+ return sizeof(x);
+ };
+
+ d2x_assert_eq(get_type_size(42), sizeof(int));
+ d2x_assert_eq(get_type_size('c'), sizeof(char));
+
+ return 0;
+}
diff --git a/solutions/cpp14/00-generic-lambdas-1.cpp b/solutions/cpp14/00-generic-lambdas-1.cpp
new file mode 100644
index 0000000..c977d7d
--- /dev/null
+++ b/solutions/cpp14/00-generic-lambdas-1.cpp
@@ -0,0 +1,52 @@
+// d2mcpp: https://github.com/mcpp-community/d2mcpp
+// license: Apache-2.0
+// reference solution for: dslings/cpp14/00-generic-lambdas-1.cpp
+//
+// 用途: 仅给 CI 与维护者参考使用,不是教程入口。
+// 教程练习入口: dslings/cpp14/00-generic-lambdas-1.cpp
+//
+
+#include
+#include
+#include
+
+int main() {
+
+ // 0. 同一个泛型 lambda 用于不同元素类型的容器排序
+ std::vector v1 = {5, 1, 4, 2, 8};
+ std::vector v2 = {3.1, 2.7, 8.5, 1.9};
+
+ auto desc = [](auto a, auto b) {
+ return a > b;
+ };
+
+ std::sort(v1.begin(), v1.end(), desc);
+ d2x_assert_eq(v1[0], 8);
+ d2x_assert_eq(v1[4], 1);
+
+ std::sort(v2.begin(), v2.end(), desc);
+ d2x_assert_eq(v2[0], 8.5);
+
+ // 1. 带捕获的泛型 lambda — find_if
+ int threshold = 3;
+ auto above = [threshold](auto x) {
+ return x > threshold;
+ };
+
+ auto it1 = std::find_if(v1.begin(), v1.end(), above);
+ d2x_assert(*it1 == 8);
+
+ auto it2 = std::find_if(v2.begin(), v2.end(), above);
+ d2x_assert(*it2 == 8.5);
+
+ // 2. 泛型 lambda 返回 lambda — 函数工厂
+ auto make_multiplier = [](auto factor) {
+ return [factor](auto x) { return x * factor; };
+ };
+
+ auto times2 = make_multiplier(2);
+ d2x_assert_eq(times2(10), 20);
+ d2x_assert_eq(times2(0.5), 1.0);
+
+ return 0;
+}
diff --git a/solutions/cpp14/xmake.lua b/solutions/cpp14/xmake.lua
new file mode 100644
index 0000000..8bbbb90
--- /dev/null
+++ b/solutions/cpp14/xmake.lua
@@ -0,0 +1,11 @@
+set_languages("cxx14")
+
+-- target: cpp14-00-generic-lambdas
+
+target("cpp14-00-generic-lambdas-0-ref")
+ set_kind("binary")
+ add_files("00-generic-lambdas-0.cpp")
+
+target("cpp14-00-generic-lambdas-1-ref")
+ set_kind("binary")
+ add_files("00-generic-lambdas-1.cpp")
From 4245822b1a4c18f0dbe40afa2d96b5f08de2a947 Mon Sep 17 00:00:00 2001
From: li-zhou <2181719471@qq.com>
Date: Tue, 16 Jun 2026 22:47:50 +0800
Subject: [PATCH 3/4] docs(cpp14): add STL real-world case and d2x setup block
to 00-generic-lambdas
- add transparent functor real-world case (std::greater<>) cited from
vendored msvc-stl/stl/inc/functional
- add collapsible d2x setup block in exercise section
- sync en book chapter
---
book/en/src/cpp14/00-generic-lambdas.md | 69 +++++++++++++++++++++++--
book/src/cpp14/00-generic-lambdas.md | 68 ++++++++++++++++++++++--
2 files changed, 131 insertions(+), 6 deletions(-)
diff --git a/book/en/src/cpp14/00-generic-lambdas.md b/book/en/src/cpp14/00-generic-lambdas.md
index 85979ed..13054f8 100644
--- a/book/en/src/cpp14/00-generic-lambdas.md
+++ b/book/en/src/cpp14/00-generic-lambdas.md
@@ -117,7 +117,51 @@ add5(10); // 15
add5(3.14); // 8.14
```
-## II. Notes
+## II. Real-World Case — Transparent Functors and Generic Lambdas in the STL
+
+> C++14 introduced transparent operator functors (e.g. `std::less<>` / `std::greater<>`) alongside generic lambdas — both motivated by the same goal: eliminating the need to hard-code concrete types. The examples below cite the vendored [MSVC STL](https://github.com/mcpp-community/d2mcpp/tree/main/msvc-stl) (source: [`msvc-stl/stl/inc/functional`](https://github.com/mcpp-community/d2mcpp/blob/main/msvc-stl/stl/inc/functional#L3420-L3429)); `_EXPORT_STD` / `requires` are internal macros and concepts and can be ignored while reading
+
+### std::greater Transparent Specialization — A Comparator That "Sees" Any Type
+
+In C++11, `std::greater` locked in the template parameter `T` — `std::greater` could only compare `int`. C++14 added `std::greater<>` (equivalent to `std::greater`), where `operator()` is itself a template accepting any comparable types:
+
+```cpp
+// MSVC STL · msvc-stl/stl/inc/functional (abridged)
+_EXPORT_STD struct greater_equal {
+ template
+ requires totally_ordered_with<_Ty1, _Ty2>
+ _NODISCARD constexpr bool operator()(_Ty1&& _Left, _Ty2&& _Right) const
+ noexcept(...) {
+ return !static_cast(static_cast<_Ty1&&>(_Left)
+ < static_cast<_Ty2&&>(_Right));
+ }
+
+ using is_transparent = int; // signals to STL algorithms: this comparator
+ // supports heterogeneous types
+};
+```
+
+The `operator()` is a template member function — exactly the same underlying mechanism as a generic lambda. The `is_transparent` tag tells algorithms like `std::sort` and `std::set`: "this comparator can compare values of different types"
+
+### Transparent Comparators and Generic Lambdas — Two Sides of the Same Coin
+
+Transparent functors and generic lambdas are interchangeable for the same use case:
+
+```cpp
+std::vector v = {5, 1, 4, 2, 8};
+
+// option 1: C++14 transparent comparator
+std::sort(v.begin(), v.end(), std::greater<>());
+
+// option 2: C++14 generic lambda
+std::sort(v.begin(), v.end(), [](auto a, auto b) { return a > b; });
+```
+
+Both eliminate the C++11 redundancy of writing separate comparators for `int`, `double`, `string`, etc.
+
+> Summary: C++14's transparent functors and generic lambdas are two expressions of the same idea — "parameterize the argument types". Transparent functors apply it to callable objects; generic lambdas apply it to lambdas. Understanding how the `is_transparent` tag connects both to STL algorithms shows why the standard library introduced these two features together in C++14
+
+## III. Notes
### A Generic Lambda Is a Class with a Templated operator()
@@ -145,7 +189,7 @@ This pattern is common with generic lambdas and is a typical use case for `declt
The parameter count is still fixed — `[](auto a, auto b)` accepts exactly two arguments. For variadic parameters, you still need variadic templates (C++20 later added support for `...` parameter packs in lambdas)
-## III. Exercise Code
+## IV. Exercise Code
### Exercise Code Topics
@@ -154,11 +198,30 @@ The parameter count is still fixed — `[](auto a, auto b)` accepts exactly two
### Exercise Auto-Checker Command
+
+Don't have d2x? Click for setup
+
+```bash
+# 1. Install xlings (Linux / macOS)
+curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash
+# Windows PowerShell:
+# irm https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.ps1 | iex
+
+# 2. Install d2x and get the tutorial
+xlings install d2x -y
+d2x install d2mcpp
+
+# 3. Enter the project directory & run the checker
+cd d2mcpp
+```
+
+
+
```
d2x checker generic-lambdas
```
-## 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/00-generic-lambdas.md b/book/src/cpp14/00-generic-lambdas.md
index d260120..a985b92 100644
--- a/book/src/cpp14/00-generic-lambdas.md
+++ b/book/src/cpp14/00-generic-lambdas.md
@@ -117,7 +117,50 @@ add5(10); // 15
add5(3.14); // 8.14
```
-## 二、注意事项
+## 二、真实案例 - STL 中的透明比较器与泛型 lambda
+
+> C++14 同步引入了**透明运算符仿函数** (transparent operator functors, 如 `std::less<>` / `std::greater<>`), 它们和泛型 lambda 是同一动机的两个出口: 都消除了"必须写死类型"的限制。下面以仓库内置的 [MSVC STL](https://github.com/mcpp-community/d2mcpp/tree/main/msvc-stl) 为例 (源码: [`msvc-stl/stl/inc/functional`](https://github.com/mcpp-community/d2mcpp/blob/main/msvc-stl/stl/inc/functional#L3420-L3429)), `_EXPORT_STD` / `requires` 是库内部宏和概念约束, 阅读时可忽略
+
+### std::greater 的透明特化 — 让比较器"看懂"任意类型
+
+C++11 的 `std::greater` 绑死了模板参数 `T`, 比如 `std::greater` 只能比较 `int`。C++14 新增了 `std::greater<>` (等价于 `std::greater`), 它的 `operator()` 本身是一个模板, 可以接受任意可比较的类型:
+
+```cpp
+// MSVC STL · msvc-stl/stl/inc/functional (有删节)
+_EXPORT_STD struct greater_equal {
+ template
+ requires totally_ordered_with<_Ty1, _Ty2>
+ _NODISCARD constexpr bool operator()(_Ty1&& _Left, _Ty2&& _Right) const
+ noexcept(...) {
+ return !static_cast(static_cast<_Ty1&&>(_Left)
+ < static_cast<_Ty2&&>(_Right));
+ }
+
+ using is_transparent = int; // 向 STL 算法声明: 此比较器支持异构类型
+};
+```
+
+`operator()` 是一个模板成员函数 — 这和泛型 lambda 的底层实现完全一致。`is_transparent` 标签告诉 `std::sort` / `std::set` 等算法: "可以用这个比较器比较不同类型的值"
+
+### 透明比较器 + 泛型 lambda — 同一场景的两种写法
+
+泛型 lambda 和透明比较器可以互换:
+
+```cpp
+std::vector v = {5, 1, 4, 2, 8};
+
+// 方式一: C++14 透明比较器
+std::sort(v.begin(), v.end(), std::greater<>());
+
+// 方式二: C++14 泛型 lambda
+std::sort(v.begin(), v.end(), [](auto a, auto b) { return a > b; });
+```
+
+两者都能避免 C++11 中为 `int` / `double` / `string` 分别写比较器的冗余
+
+> 小结: C++14 的透明比较器和泛型 lambda 都是 "参数类型参数化" 思路的产物 — 一个作用在仿函数上, 一个作用在 lambda 上。理解了两者共用 `is_transparent` 标签和 STL 算法的配合方式, 就能明白标准库为什么要同时引入这两个特性
+
+## 三、注意事项
### 泛型 lambda 是一个有模板 operator() 的类
@@ -145,7 +188,7 @@ auto forwarder = [](auto&& x) -> decltype(auto) {
泛型 lambda 的参数个数仍然是固定的 — `[](auto a, auto b)` 接受恰好两个参数。如果要变参, 仍然需要可变参数模板 (C++20 后才支持 lambda 中使用 `...` 参数包)
-## 三、练习代码
+## 四、练习代码
### 练习代码主题
@@ -154,11 +197,30 @@ auto forwarder = [](auto&& x) -> decltype(auto) {
### 练习代码自动检测命令
+
+还没有 d2x?点击展开获取方式
+
+```bash
+# 1. 安装 xlings(Linux / macOS)
+curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash
+# Windows PowerShell:
+# irm https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.ps1 | iex
+
+# 2. 安装 d2x 并拉取本教程
+xlings install d2x -y
+d2x install d2mcpp
+
+# 3. 进入项目目录 & 运行检查命令
+cd d2mcpp
+```
+
+
+
```
d2x checker generic-lambdas
```
-## 四、其他
+## 五、其他
- [交流讨论](https://forum.d2learn.org/category/20)
- [d2mcpp教程仓库](https://github.com/mcpp-community/d2mcpp)
From de16c08c2ac742e8e16706b7131dc11722941329 Mon Sep 17 00:00:00 2001
From: li-zhou <2181719471@qq.com>
Date: Wed, 17 Jun 2026 10:58:06 +0800
Subject: [PATCH 4/4] docs(cpp14): fix Copilot review findings in
00-generic-lambdas
- fix C++11 example using auto (C++14 feature) in EN Why-introduced
- fix variadic claim: generic lambdas can be variadic in C++14
- fix STL case: use greater from xutility instead of greater_equal
- fix is_transparent description: it signals associative containers,
not sort algorithms
---
book/en/src/cpp14/00-generic-lambdas.md | 26 ++++++++++++-------------
book/src/cpp14/00-generic-lambdas.md | 23 +++++++++++-----------
2 files changed, 23 insertions(+), 26 deletions(-)
diff --git a/book/en/src/cpp14/00-generic-lambdas.md b/book/en/src/cpp14/00-generic-lambdas.md
index 13054f8..612e50e 100644
--- a/book/en/src/cpp14/00-generic-lambdas.md
+++ b/book/en/src/cpp14/00-generic-lambdas.md
@@ -18,7 +18,7 @@ C++14 allows lambda parameters to use `auto`, turning the lambda's `operator()`
**Why introduced?**
- In C++11, lambda parameter types must be explicitly specified — the same lambda cannot be reused for different argument types because `operator()` is a plain member function, not a template
-- Many lambdas express type-independent logic (e.g. `[](auto a, auto b) { return a < b; }` works for `int`, `double`, `string`), but C++11 required writing a separate lambda for each type
+- Many lambdas express type-independent logic (e.g. comparing two values), but C++11 required writing separate lambdas for each concrete type (e.g. `[](int a, int b) { return a < b; }` for int, `[](double a, double b) { return a < b; }` for double)
- C++14 allows `auto` in lambda parameters; the compiler generates an implicit template for `operator()`, essentially bringing function templates into the lambda world
**How does it work?**
@@ -119,29 +119,27 @@ add5(3.14); // 8.14
## II. Real-World Case — Transparent Functors and Generic Lambdas in the STL
-> C++14 introduced transparent operator functors (e.g. `std::less<>` / `std::greater<>`) alongside generic lambdas — both motivated by the same goal: eliminating the need to hard-code concrete types. The examples below cite the vendored [MSVC STL](https://github.com/mcpp-community/d2mcpp/tree/main/msvc-stl) (source: [`msvc-stl/stl/inc/functional`](https://github.com/mcpp-community/d2mcpp/blob/main/msvc-stl/stl/inc/functional#L3420-L3429)); `_EXPORT_STD` / `requires` are internal macros and concepts and can be ignored while reading
+> C++14 introduced transparent operator functors (e.g. `std::less<>` / `std::greater<>`) alongside generic lambdas — both motivated by the same goal: eliminating the need to hard-code concrete types. The examples below cite the vendored [MSVC STL](https://github.com/mcpp-community/d2mcpp/tree/main/msvc-stl) (source: [`msvc-stl/stl/inc/xutility`](https://github.com/mcpp-community/d2mcpp/blob/main/msvc-stl/stl/inc/xutility#L902-L912)); `_NODISCARD` / `constexpr` are internal annotations and can be ignored while reading
### std::greater Transparent Specialization — A Comparator That "Sees" Any Type
In C++11, `std::greater` locked in the template parameter `T` — `std::greater` could only compare `int`. C++14 added `std::greater<>` (equivalent to `std::greater`), where `operator()` is itself a template accepting any comparable types:
```cpp
-// MSVC STL · msvc-stl/stl/inc/functional (abridged)
-_EXPORT_STD struct greater_equal {
+// MSVC STL · msvc-stl/stl/inc/xutility (abridged)
+template <>
+struct greater {
template
- requires totally_ordered_with<_Ty1, _Ty2>
- _NODISCARD constexpr bool operator()(_Ty1&& _Left, _Ty2&& _Right) const
- noexcept(...) {
- return !static_cast(static_cast<_Ty1&&>(_Left)
- < static_cast<_Ty2&&>(_Right));
+ _NODISCARD constexpr auto operator()(_Ty1&& _Left, _Ty2&& _Right) const
+ noexcept(...) -> decltype(static_cast<_Ty1&&>(_Left) > static_cast<_Ty2&&>(_Right)) {
+ return static_cast<_Ty1&&>(_Left) > static_cast<_Ty2&&>(_Right);
}
- using is_transparent = int; // signals to STL algorithms: this comparator
- // supports heterogeneous types
+ using is_transparent = int;
};
```
-The `operator()` is a template member function — exactly the same underlying mechanism as a generic lambda. The `is_transparent` tag tells algorithms like `std::sort` and `std::set`: "this comparator can compare values of different types"
+The `operator()` is a template member function — exactly the same underlying mechanism as a generic lambda. The `is_transparent` tag signals to associative containers like `std::set` and `std::map` that this comparator supports heterogeneous lookup, allowing a `std::string` to be used to search a `std::set` without constructing a temporary object
### Transparent Comparators and Generic Lambdas — Two Sides of the Same Coin
@@ -185,9 +183,9 @@ auto forwarder = [](auto&& x) -> decltype(auto) {
This pattern is common with generic lambdas and is a typical use case for `decltype(auto)` (another C++14 feature)
-### Generic Lambdas Are Not Variadic
+### Generic Lambdas Can Be Variadic
-The parameter count is still fixed — `[](auto a, auto b)` accepts exactly two arguments. For variadic parameters, you still need variadic templates (C++20 later added support for `...` parameter packs in lambdas)
+C++14 generic lambdas support parameter packs — `[](auto... xs)` accepts any number (and types) of arguments. The compiler generates a templated `operator()` with a parameter pack. C++20 later added explicit template parameter lists for lambdas (`[](Ts... xs)`), but variadic generic lambdas were already usable in C++14
## IV. Exercise Code
diff --git a/book/src/cpp14/00-generic-lambdas.md b/book/src/cpp14/00-generic-lambdas.md
index a985b92..892b39c 100644
--- a/book/src/cpp14/00-generic-lambdas.md
+++ b/book/src/cpp14/00-generic-lambdas.md
@@ -119,28 +119,27 @@ add5(3.14); // 8.14
## 二、真实案例 - STL 中的透明比较器与泛型 lambda
-> C++14 同步引入了**透明运算符仿函数** (transparent operator functors, 如 `std::less<>` / `std::greater<>`), 它们和泛型 lambda 是同一动机的两个出口: 都消除了"必须写死类型"的限制。下面以仓库内置的 [MSVC STL](https://github.com/mcpp-community/d2mcpp/tree/main/msvc-stl) 为例 (源码: [`msvc-stl/stl/inc/functional`](https://github.com/mcpp-community/d2mcpp/blob/main/msvc-stl/stl/inc/functional#L3420-L3429)), `_EXPORT_STD` / `requires` 是库内部宏和概念约束, 阅读时可忽略
+> C++14 同步引入了**透明运算符仿函数** (transparent operator functors, 如 `std::less<>` / `std::greater<>`), 它们和泛型 lambda 是同一动机的两个出口: 都消除了"必须写死类型"的限制。下面以仓库内置的 [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#L902-L912)), `_NODISCARD` / `constexpr` 是库内部标注, 阅读时可忽略
### std::greater 的透明特化 — 让比较器"看懂"任意类型
C++11 的 `std::greater` 绑死了模板参数 `T`, 比如 `std::greater` 只能比较 `int`。C++14 新增了 `std::greater<>` (等价于 `std::greater`), 它的 `operator()` 本身是一个模板, 可以接受任意可比较的类型:
```cpp
-// MSVC STL · msvc-stl/stl/inc/functional (有删节)
-_EXPORT_STD struct greater_equal {
+// MSVC STL · msvc-stl/stl/inc/xutility (有删节)
+template <>
+struct greater {
template
- requires totally_ordered_with<_Ty1, _Ty2>
- _NODISCARD constexpr bool operator()(_Ty1&& _Left, _Ty2&& _Right) const
- noexcept(...) {
- return !static_cast(static_cast<_Ty1&&>(_Left)
- < static_cast<_Ty2&&>(_Right));
+ _NODISCARD constexpr auto operator()(_Ty1&& _Left, _Ty2&& _Right) const
+ noexcept(...) -> decltype(static_cast<_Ty1&&>(_Left) > static_cast<_Ty2&&>(_Right)) {
+ return static_cast<_Ty1&&>(_Left) > static_cast<_Ty2&&>(_Right);
}
- using is_transparent = int; // 向 STL 算法声明: 此比较器支持异构类型
+ using is_transparent = int;
};
```
-`operator()` 是一个模板成员函数 — 这和泛型 lambda 的底层实现完全一致。`is_transparent` 标签告诉 `std::sort` / `std::set` 等算法: "可以用这个比较器比较不同类型的值"
+`operator()` 是一个模板成员函数 — 这和泛型 lambda 的底层实现完全一致。`is_transparent` 标签向 `std::set` / `std::map` 等关联容器声明此比较器支持异构查找, 可以直接用 `std::string` 查找 `std::set` 而不需要构造临时对象
### 透明比较器 + 泛型 lambda — 同一场景的两种写法
@@ -184,9 +183,9 @@ auto forwarder = [](auto&& x) -> decltype(auto) {
这种写法在泛型 lambda 里很常见, 也是 `decltype(auto)` (C++14 的另一特性) 的典型使用场景
-### 泛型 lambda 不是 variadic
+### 泛型 lambda 可以是 variadic
-泛型 lambda 的参数个数仍然是固定的 — `[](auto a, auto b)` 接受恰好两个参数。如果要变参, 仍然需要可变参数模板 (C++20 后才支持 lambda 中使用 `...` 参数包)
+C++14 的泛型 lambda 支持参数包 — `[](auto... xs)` 可以接受任意数量(和类型)的参数, 编译器为 `operator()` 生成带参数包的模板。C++20 进一步允许显式模板参数列表 (`[](Ts... xs)`), 但变参泛型 lambda 在 C++14 就已经可用
## 四、练习代码