Skip to content

Commit c387004

Browse files
committed
docs(cpp14): add 00-generic-lambdas book chapter and build wiring
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)
1 parent c403bad commit c387004

9 files changed

Lines changed: 340 additions & 1 deletion

File tree

book/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
**现代C++标准(cppref)**
22

33
- C++11: [](https://zh.cppreference.com/w/cpp/11) / [En](https://en.cppreference.com/w/cpp/11)
4+
- C++14: [](https://zh.cppreference.com/w/cpp/14) / [En](https://en.cppreference.com/w/cpp/14)

book/en/src/SUMMARY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030

3131
# C++14 Core Language Features
3232

33+
- [Generic Lambdas](./cpp14/00-generic-lambdas.md)
34+
3335
# Additional Resources
3436

3537
- [Changelog](changelog.md)
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
<div align=right>
2+
3+
🌎 [中文] | [English]
4+
</div>
5+
6+
[中文]: ../../cpp14/00-generic-lambdas.html
7+
[English]: ./00-generic-lambdas.html
8+
9+
# Generic Lambdas
10+
11+
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
12+
13+
| Book | Video | Code | X |
14+
| --- | --- | --- | --- |
15+
| [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) | |
16+
17+
18+
**Why introduced?**
19+
20+
- 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
21+
- 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
22+
- C++14 allows `auto` in lambda parameters; the compiler generates an implicit template for `operator()`, essentially bringing function templates into the lambda world
23+
24+
**How does it work?**
25+
26+
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:
27+
28+
```cpp
29+
struct __lambda {
30+
template <typename T1, typename T2>
31+
auto operator()(T1 a, T2 b) const {
32+
return a + b;
33+
}
34+
};
35+
```
36+
37+
## I. Basic Usage and Scenarios
38+
39+
### Simple Generic Lambda
40+
41+
> Declare lambda parameters with auto; the compiler generates operator() instances based on the argument types at the call site
42+
43+
```cpp
44+
auto identity = [](auto x) {
45+
return x;
46+
};
47+
48+
int i = identity(42); // x deduced as int
49+
double d = identity(3.14); // x deduced as double
50+
```
51+
52+
### Multi-Parameter Generic Lambda
53+
54+
```cpp
55+
auto add = [](auto a, auto b) {
56+
return a + b;
57+
};
58+
59+
add(1, 2); // int + int
60+
add(1.5, 2.5); // double + double
61+
add(std::string("hello "), std::string("world")); // string + string
62+
```
63+
64+
Each parameter's type is deduced independently; `T1` and `T2` can differ:
65+
66+
```cpp
67+
auto multiply = [](auto a, auto b) {
68+
return a * b;
69+
};
70+
71+
multiply(2, 3.5); // int * double → double
72+
```
73+
74+
### Generic Lambda + STL Algorithms
75+
76+
The most common use case — avoid writing identical logic for every container element type:
77+
78+
```cpp
79+
std::vector<int> v1 = {5, 1, 4, 2, 8};
80+
std::vector<double> v2 = {3.1, 2.7, 8.5, 1.9};
81+
82+
// C++11: write separate lambdas for int and double
83+
std::sort(v1.begin(), v1.end(), [](int a, int b) { return a > b; });
84+
std::sort(v2.begin(), v2.end(), [](double a, double b) { return a > b; });
85+
86+
// C++14: a single generic lambda handles both
87+
auto gt = [](auto a, auto b) { return a > b; };
88+
std::sort(v1.begin(), v1.end(), gt);
89+
std::sort(v2.begin(), v2.end(), gt);
90+
```
91+
92+
### Generic Lambda with Captures
93+
94+
Captured variables keep their concrete types; only parameters use `auto`:
95+
96+
```cpp
97+
int threshold = 10;
98+
auto above = [threshold](auto x) {
99+
return x > threshold; // threshold is int, x is generic
100+
};
101+
102+
above(20); // x = int
103+
above(3.5); // x = double
104+
```
105+
106+
### Generic Lambda Returning Lambda
107+
108+
A generic lambda can return a new lambda, creating a function factory:
109+
110+
```cpp
111+
auto make_adder = [](auto n) {
112+
return [n](auto x) { return x + n; }; // C++14 supports this
113+
};
114+
115+
auto add5 = make_adder(5);
116+
add5(10); // 15
117+
add5(3.14); // 8.14
118+
```
119+
120+
## II. Notes
121+
122+
### A Generic Lambda Is a Class with a Templated operator()
123+
124+
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
125+
126+
```cpp
127+
auto f = [](auto x) { return x; };
128+
auto g = [](auto x) { return x; };
129+
// f and g have different types; cannot be assigned to each other
130+
```
131+
132+
### Generic Parameters and Perfect Forwarding
133+
134+
Generic lambda parameter deduction strips references and const by default. Use `auto&&` with `std::forward` to preserve them:
135+
136+
```cpp
137+
auto forwarder = [](auto&& x) -> decltype(auto) {
138+
return std::forward<decltype(x)>(x);
139+
};
140+
```
141+
142+
This pattern is common with generic lambdas and is a typical use case for `decltype(auto)` (another C++14 feature)
143+
144+
### Generic Lambdas Are Not Variadic
145+
146+
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)
147+
148+
## III. Exercise Code
149+
150+
### Exercise Code Topics
151+
152+
- 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)
153+
- 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)
154+
155+
### Exercise Auto-Checker Command
156+
157+
```
158+
d2x checker generic-lambdas
159+
```
160+
161+
## IV. Other
162+
163+
- [Discussion Forum](https://forum.d2learn.org/category/20)
164+
- [d2mcpp Tutorial Repository](https://github.com/mcpp-community/d2mcpp)
165+
- [Tutorial Video List](https://space.bilibili.com/65858958/lists/5208246)
166+
- [Tutorial Support Tool - xlings](https://github.com/openxlings/xlings)

book/src/SUMMARY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030

3131
# C++14核心语言特性
3232

33+
- [泛型 lambda - generic lambdas](./cpp14/00-generic-lambdas.md)
34+
3335
# 其他
3436

3537
- [更新日志](changelog.md)
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
<div align=right>
2+
3+
🌎 [中文] | [English]
4+
</div>
5+
6+
[中文]: ./00-generic-lambdas.html
7+
[English]: ../en/cpp14/00-generic-lambdas.html
8+
9+
# 泛型 lambda - generic lambdas
10+
11+
泛型 lambda 是 C++14 在 lambda 表达式上引入的一项重要增强, 允许 lambda 的参数使用 `auto` 类型推导, 使得一个 lambda 表达式可以像函数模板一样处理不同类型的参数
12+
13+
| Book | Video | Code | X |
14+
| --- | --- | --- | --- |
15+
| [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) | |
16+
17+
18+
**为什么引入?**
19+
20+
- C++11 的 lambda 参数类型必须显式指定, 同一个 lambda 无法复用于不同类型的参数 — 本质上 lambda 的 `operator()` 是一个普通成员函数, 不能是模板
21+
- 在实际编码中, 很多 lambda 的逻辑与类型无关 (例如 `[](int a, int b) { return a < b; }` 中的比较逻辑对 `int` / `double` / `string` 都适用), 但 C++11 要求为每种类型写一份
22+
- C++14 允许 lambda 参数使用 `auto`, 编译器会为 `operator()` 生成一个隐式的模板, 每种参数类型实例化一份 — 相当于把"函数模板"带到了 lambda 世界里
23+
24+
**泛型 lambda 是如何实现的?**
25+
26+
编译器将泛型 lambda 展开为一个带有**模板化 `operator()`** 的仿函数类。例如 `[](auto a, auto b) { return a + b; }` 在内部等价于:
27+
28+
```cpp
29+
struct __lambda {
30+
template <typename T1, typename T2>
31+
auto operator()(T1 a, T2 b) const {
32+
return a + b;
33+
}
34+
};
35+
```
36+
37+
## 一、基础用法和场景
38+
39+
### 简单泛型 lambda
40+
41+
> lambda 参数用 auto 声明, 编译器根据调用时的实参类型生成对应的 operator() 实例
42+
43+
```cpp
44+
auto identity = [](auto x) {
45+
return x;
46+
};
47+
48+
int i = identity(42); // x 推导为 int
49+
double d = identity(3.14); // x 推导为 double
50+
```
51+
52+
### 多参数泛型 lambda
53+
54+
```cpp
55+
auto add = [](auto a, auto b) {
56+
return a + b;
57+
};
58+
59+
add(1, 2); // int + int
60+
add(1.5, 2.5); // double + double
61+
add(std::string("hello "), std::string("world")); // string + string
62+
```
63+
64+
每个参数的类型是独立推导的, `T1` 和 `T2` 可以不同:
65+
66+
```cpp
67+
auto multiply = [](auto a, auto b) {
68+
return a * b;
69+
};
70+
71+
multiply(2, 3.5); // int * double → double
72+
```
73+
74+
### 泛型 lambda + STL 算法
75+
76+
泛型 lambda 最常见的应用场景是配合 STL 算法, 避免为每种容器元素类型重复编写相同逻辑的比较/判据:
77+
78+
```cpp
79+
std::vector<int> v1 = {5, 1, 4, 2, 8};
80+
std::vector<double> v2 = {3.1, 2.7, 8.5, 1.9};
81+
82+
// C++11: 需要为 int 和 double 分别写 lambda
83+
std::sort(v1.begin(), v1.end(), [](int a, int b) { return a > b; });
84+
std::sort(v2.begin(), v2.end(), [](double a, double b) { return a > b; });
85+
86+
// C++14: 同一个泛型 lambda 搞定
87+
auto gt = [](auto a, auto b) { return a > b; };
88+
std::sort(v1.begin(), v1.end(), gt);
89+
std::sort(v2.begin(), v2.end(), gt);
90+
```
91+
92+
### 带捕获的泛型 lambda
93+
94+
捕获的变量类型不变, 只有参数用 `auto`:
95+
96+
```cpp
97+
int threshold = 10;
98+
auto above = [threshold](auto x) {
99+
return x > threshold; // threshold 捕获为 int, x 是泛型参数
100+
};
101+
102+
above(20); // x = int
103+
above(3.5); // x = double
104+
```
105+
106+
### 泛型 lambda 返回 lambda
107+
108+
泛型 lambda 可以返回一个新 lambda, 实现类似"函数工厂"的效果:
109+
110+
```cpp
111+
auto make_adder = [](auto n) {
112+
return [n](auto x) { return x + n; }; // C++14 支持, 返回类型自动推导
113+
};
114+
115+
auto add5 = make_adder(5);
116+
add5(10); // 15
117+
add5(3.14); // 8.14
118+
```
119+
120+
## 二、注意事项
121+
122+
### 泛型 lambda 是一个有模板 operator() 的类
123+
124+
每个泛型 lambda 表达式产生一个独立的闭包类型。即使是写法完全相同的两个泛型 lambda, 它们的类型也不同 — 这和普通 lambda 的规则一样, 但泛型 lambda 的 `operator()` 是模板, 所以同一类型可以接受不同参数类型
125+
126+
```cpp
127+
auto f = [](auto x) { return x; };
128+
auto g = [](auto x) { return x; };
129+
// f 和 g 的类型不同, 不能互相赋值
130+
```
131+
132+
### 泛型参数和完美转发
133+
134+
泛型 lambda 的参数推导默认剥离引用和 const, 需要完整保留时用 `auto&&` 配合 `std::forward`:
135+
136+
```cpp
137+
auto forwarder = [](auto&& x) -> decltype(auto) {
138+
return std::forward<decltype(x)>(x);
139+
};
140+
```
141+
142+
这种写法在泛型 lambda 里很常见, 也是 `decltype(auto)` (C++14 的另一特性) 的典型使用场景
143+
144+
### 泛型 lambda 不是 variadic
145+
146+
泛型 lambda 的参数个数仍然是固定的 — `[](auto a, auto b)` 接受恰好两个参数。如果要变参, 仍然需要可变参数模板 (C++20 后才支持 lambda 中使用 `...` 参数包)
147+
148+
## 三、练习代码
149+
150+
### 练习代码主题
151+
152+
- 0 - [泛型 lambda 基础 — auto 参数与类型推导](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp14/00-generic-lambdas-0.cpp)
153+
- 1 - [泛型 lambda 与 STL 算法 — 排序、查找、函数工厂](https://github.com/mcpp-community/d2mcpp/blob/main/dslings/cpp14/00-generic-lambdas-1.cpp)
154+
155+
### 练习代码自动检测命令
156+
157+
```
158+
d2x checker generic-lambdas
159+
```
160+
161+
## 四、其他
162+
163+
- [交流讨论](https://forum.d2learn.org/category/20)
164+
- [d2mcpp教程仓库](https://github.com/mcpp-community/d2mcpp)
165+
- [教程视频列表](https://space.bilibili.com/65858958/lists/5208246)
166+
- [教程支持工具-xlings](https://github.com/openxlings/xlings)

dslings/cpp14/README.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

dslings/en/xmake.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ target("00-0-hello-mcpp")
33
add_files("hello-mcpp.cpp")
44

55
includes("cpp11")
6+
includes("cpp14")

dslings/xmake.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ if lang == "zh" then
1717
add_files("hello-mcpp.cpp")
1818

1919
includes("cpp11")
20+
includes("cpp14")
2021
else
2122
includes("en")
2223
end

solutions/xmake.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@
88
-- contributors, not the compiler, so we keep a single zh-style copy.
99

1010
includes("cpp11/xmake.lua")
11+
includes("cpp14/xmake.lua")

0 commit comments

Comments
 (0)