Skip to content

Commit 4245822

Browse files
committed
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
1 parent 3fa0d39 commit 4245822

2 files changed

Lines changed: 131 additions & 6 deletions

File tree

book/en/src/cpp14/00-generic-lambdas.md

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,51 @@ add5(10); // 15
117117
add5(3.14); // 8.14
118118
```
119119
120-
## II. Notes
120+
## II. Real-World Case — Transparent Functors and Generic Lambdas in the STL
121+
122+
> 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
123+
124+
### std::greater Transparent Specialization — A Comparator That "Sees" Any Type
125+
126+
In C++11, `std::greater<T>` locked in the template parameter `T` — `std::greater<int>` could only compare `int`. C++14 added `std::greater<>` (equivalent to `std::greater<void>`), where `operator()` is itself a template accepting any comparable types:
127+
128+
```cpp
129+
// MSVC STL · msvc-stl/stl/inc/functional (abridged)
130+
_EXPORT_STD struct greater_equal {
131+
template <class _Ty1, class _Ty2>
132+
requires totally_ordered_with<_Ty1, _Ty2>
133+
_NODISCARD constexpr bool operator()(_Ty1&& _Left, _Ty2&& _Right) const
134+
noexcept(...) {
135+
return !static_cast<bool>(static_cast<_Ty1&&>(_Left)
136+
< static_cast<_Ty2&&>(_Right));
137+
}
138+
139+
using is_transparent = int; // signals to STL algorithms: this comparator
140+
// supports heterogeneous types
141+
};
142+
```
143+
144+
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"
145+
146+
### Transparent Comparators and Generic Lambdas — Two Sides of the Same Coin
147+
148+
Transparent functors and generic lambdas are interchangeable for the same use case:
149+
150+
```cpp
151+
std::vector<int> v = {5, 1, 4, 2, 8};
152+
153+
// option 1: C++14 transparent comparator
154+
std::sort(v.begin(), v.end(), std::greater<>());
155+
156+
// option 2: C++14 generic lambda
157+
std::sort(v.begin(), v.end(), [](auto a, auto b) { return a > b; });
158+
```
159+
160+
Both eliminate the C++11 redundancy of writing separate comparators for `int`, `double`, `string`, etc.
161+
162+
> 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
163+
164+
## III. Notes
121165
122166
### A Generic Lambda Is a Class with a Templated operator()
123167
@@ -145,7 +189,7 @@ This pattern is common with generic lambdas and is a typical use case for `declt
145189
146190
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)
147191
148-
## III. Exercise Code
192+
## IV. Exercise Code
149193
150194
### Exercise Code Topics
151195
@@ -154,11 +198,30 @@ The parameter count is still fixed — `[](auto a, auto b)` accepts exactly two
154198
155199
### Exercise Auto-Checker Command
156200
201+
<details>
202+
<summary>Don't have d2x? Click for setup</summary>
203+
204+
```bash
205+
# 1. Install xlings (Linux / macOS)
206+
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash
207+
# Windows PowerShell:
208+
# irm https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.ps1 | iex
209+
210+
# 2. Install d2x and get the tutorial
211+
xlings install d2x -y
212+
d2x install d2mcpp
213+
214+
# 3. Enter the project directory & run the checker
215+
cd d2mcpp
216+
```
217+
218+
</details>
219+
157220
```
158221
d2x checker generic-lambdas
159222
```
160223

161-
## IV. Other
224+
## V. Other
162225

163226
- [Discussion Forum](https://forum.d2learn.org/category/20)
164227
- [d2mcpp Tutorial Repository](https://github.com/mcpp-community/d2mcpp)

book/src/cpp14/00-generic-lambdas.md

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,50 @@ add5(10); // 15
117117
add5(3.14); // 8.14
118118
```
119119
120-
## 二、注意事项
120+
## 二、真实案例 - STL 中的透明比较器与泛型 lambda
121+
122+
> 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` 是库内部宏和概念约束, 阅读时可忽略
123+
124+
### std::greater 的透明特化 — 让比较器"看懂"任意类型
125+
126+
C++11 的 `std::greater<T>` 绑死了模板参数 `T`, 比如 `std::greater<int>` 只能比较 `int`。C++14 新增了 `std::greater<>` (等价于 `std::greater<void>`), 它的 `operator()` 本身是一个模板, 可以接受任意可比较的类型:
127+
128+
```cpp
129+
// MSVC STL · msvc-stl/stl/inc/functional (有删节)
130+
_EXPORT_STD struct greater_equal {
131+
template <class _Ty1, class _Ty2>
132+
requires totally_ordered_with<_Ty1, _Ty2>
133+
_NODISCARD constexpr bool operator()(_Ty1&& _Left, _Ty2&& _Right) const
134+
noexcept(...) {
135+
return !static_cast<bool>(static_cast<_Ty1&&>(_Left)
136+
< static_cast<_Ty2&&>(_Right));
137+
}
138+
139+
using is_transparent = int; // 向 STL 算法声明: 此比较器支持异构类型
140+
};
141+
```
142+
143+
`operator()` 是一个模板成员函数 — 这和泛型 lambda 的底层实现完全一致。`is_transparent` 标签告诉 `std::sort` / `std::set` 等算法: "可以用这个比较器比较不同类型的值"
144+
145+
### 透明比较器 + 泛型 lambda — 同一场景的两种写法
146+
147+
泛型 lambda 和透明比较器可以互换:
148+
149+
```cpp
150+
std::vector<int> v = {5, 1, 4, 2, 8};
151+
152+
// 方式一: C++14 透明比较器
153+
std::sort(v.begin(), v.end(), std::greater<>());
154+
155+
// 方式二: C++14 泛型 lambda
156+
std::sort(v.begin(), v.end(), [](auto a, auto b) { return a > b; });
157+
```
158+
159+
两者都能避免 C++11 中为 `int` / `double` / `string` 分别写比较器的冗余
160+
161+
> 小结: C++14 的透明比较器和泛型 lambda 都是 "参数类型参数化" 思路的产物 — 一个作用在仿函数上, 一个作用在 lambda 上。理解了两者共用 `is_transparent` 标签和 STL 算法的配合方式, 就能明白标准库为什么要同时引入这两个特性
162+
163+
## 三、注意事项
121164
122165
### 泛型 lambda 是一个有模板 operator() 的类
123166
@@ -145,7 +188,7 @@ auto forwarder = [](auto&& x) -> decltype(auto) {
145188
146189
泛型 lambda 的参数个数仍然是固定的 — `[](auto a, auto b)` 接受恰好两个参数。如果要变参, 仍然需要可变参数模板 (C++20 后才支持 lambda 中使用 `...` 参数包)
147190
148-
## 、练习代码
191+
## 、练习代码
149192
150193
### 练习代码主题
151194
@@ -154,11 +197,30 @@ auto forwarder = [](auto&& x) -> decltype(auto) {
154197
155198
### 练习代码自动检测命令
156199
200+
<details>
201+
<summary>还没有 d2x?点击展开获取方式</summary>
202+
203+
```bash
204+
# 1. 安装 xlings(Linux / macOS)
205+
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash
206+
# Windows PowerShell:
207+
# irm https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.ps1 | iex
208+
209+
# 2. 安装 d2x 并拉取本教程
210+
xlings install d2x -y
211+
d2x install d2mcpp
212+
213+
# 3. 进入项目目录 & 运行检查命令
214+
cd d2mcpp
215+
```
216+
217+
</details>
218+
157219
```
158220
d2x checker generic-lambdas
159221
```
160222

161-
## 、其他
223+
## 、其他
162224

163225
- [交流讨论](https://forum.d2learn.org/category/20)
164226
- [d2mcpp教程仓库](https://github.com/mcpp-community/d2mcpp)

0 commit comments

Comments
 (0)