Skip to content

Commit 3fa0d39

Browse files
committed
feat(cpp14): add 00-generic-lambdas exercises and solutions
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<int> and vector<double> 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 <string>. ex 1 layers (2) and (3) on top. The desc lambda applied to both vector<int> and vector<double> 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
1 parent c387004 commit 3fa0d39

9 files changed

Lines changed: 374 additions & 0 deletions

File tree

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// d2mcpp: https://github.com/mcpp-community/d2mcpp
2+
// license: Apache-2.0
3+
// file: dslings/cpp14/00-generic-lambdas-0.cpp
4+
//
5+
// Exercise/练习: cpp14 | 00 - generic lambdas | 泛型 lambda
6+
//
7+
// Tips/提示:
8+
// - lambda 参数使用 auto, 编译器为 operator() 生成隐式模板
9+
// - 同一个泛型 lambda 可以接受不同类型的参数
10+
//
11+
// Docs/文档:
12+
// - https://en.cppreference.com/w/cpp/language/lambda
13+
// - https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp14/00-generic-lambdas.md
14+
//
15+
// 练习交流讨论: http://forum.d2learn.org/category/20
16+
//
17+
// Auto-Checker/自动检测命令:
18+
//
19+
// d2x checker generic-lambdas
20+
//
21+
22+
#include <d2x/cpp/common.hpp>
23+
#include <string>
24+
25+
int main() {
26+
27+
// 0. 简单泛型 lambda — identity
28+
auto identity = [](D2X_YOUR_ANSWER x) {
29+
return x;
30+
};
31+
32+
d2x_assert_eq(identity(42), 42);
33+
d2x_assert(identity(std::string("hello")) == "hello");
34+
d2x_assert_eq(identity(3.14), D2X_YOUR_ANSWER);
35+
36+
// 1. 泛型 lambda 做比较
37+
auto greater = [](auto a, auto b) {
38+
return D2X_YOUR_ANSWER;
39+
};
40+
41+
d2x_assert(greater(5, 3));
42+
d2x_assert(greater(2.5, 1.2));
43+
d2x_assert(greater(std::string("z"), std::string("a")));
44+
45+
// 2. 推导类型确认
46+
auto get_type_size = [](auto x) {
47+
return sizeof(D2X_YOUR_ANSWER);
48+
};
49+
50+
d2x_assert_eq(get_type_size(42), sizeof(int));
51+
d2x_assert_eq(get_type_size('c'), sizeof(char));
52+
53+
D2X_WAIT
54+
55+
return 0;
56+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// d2mcpp: https://github.com/mcpp-community/d2mcpp
2+
// license: Apache-2.0
3+
// file: dslings/cpp14/00-generic-lambdas-1.cpp
4+
//
5+
// Exercise/练习: cpp14 | 00 - generic lambdas | 泛型 lambda 与 STL 算法
6+
//
7+
// Tips/提示:
8+
// - 泛型 lambda 可复用于不同元素类型的容器, 同一个 lambda 传给多种 STL 算法
9+
// - 捕获的变量类型不变, 只有参数用 auto
10+
//
11+
// Docs/文档:
12+
// - https://en.cppreference.com/w/cpp/language/lambda
13+
// - https://github.com/mcpp-community/d2mcpp/blob/main/book/src/cpp14/00-generic-lambdas.md
14+
//
15+
// 练习交流讨论: http://forum.d2learn.org/category/20
16+
//
17+
// Auto-Checker/自动检测命令:
18+
//
19+
// d2x checker generic-lambdas
20+
//
21+
22+
#include <d2x/cpp/common.hpp>
23+
#include <vector>
24+
#include <algorithm>
25+
26+
int main() {
27+
28+
// 0. 同一个泛型 lambda 用于不同元素类型的容器排序
29+
std::vector<int> v1 = {5, 1, 4, 2, 8};
30+
std::vector<double> v2 = {3.1, 2.7, 8.5, 1.9};
31+
32+
auto desc = [](D2X_YOUR_ANSWER a, D2X_YOUR_ANSWER b) {
33+
return a > b;
34+
};
35+
36+
std::sort(v1.begin(), v1.end(), desc);
37+
d2x_assert_eq(v1[0], 8);
38+
d2x_assert_eq(v1[4], 1);
39+
40+
std::sort(v2.begin(), v2.end(), desc);
41+
d2x_assert_eq(v2[0], D2X_YOUR_ANSWER);
42+
43+
// 1. 带捕获的泛型 lambda — find_if
44+
int threshold = 3;
45+
auto above = [threshold](auto x) {
46+
return x > threshold;
47+
};
48+
49+
auto it1 = std::find_if(v1.begin(), v1.end(), above);
50+
d2x_assert(*it1 == D2X_YOUR_ANSWER);
51+
52+
auto it2 = std::find_if(v2.begin(), v2.end(), above);
53+
d2x_assert(*it2 == 8.5);
54+
55+
// 2. 泛型 lambda 返回 lambda — 函数工厂
56+
auto make_multiplier = [](auto factor) {
57+
return [factor](auto x) { return x * D2X_YOUR_ANSWER; };
58+
};
59+
60+
auto times2 = make_multiplier(2);
61+
d2x_assert_eq(times2(10), 20);
62+
d2x_assert_eq(times2(0.5), 1.0);
63+
64+
D2X_WAIT
65+
66+
return 0;
67+
}

dslings/cpp14/xmake.lua

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
set_languages("cxx14")
2+
3+
-- target: cpp14-00-generic-lambdas
4+
5+
target("cpp14-00-generic-lambdas-0")
6+
set_kind("binary")
7+
add_files("00-generic-lambdas-0.cpp")
8+
9+
target("cpp14-00-generic-lambdas-1")
10+
set_kind("binary")
11+
add_files("00-generic-lambdas-1.cpp")
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// d2mcpp: https://github.com/mcpp-community/d2mcpp
2+
// license: Apache-2.0
3+
// file: dslings/en/cpp14/00-generic-lambdas-0.cpp
4+
//
5+
// Exercise: cpp14 | 00 - generic lambdas | basic generic lambda
6+
//
7+
// Tips:
8+
// - Use auto in lambda parameters; the compiler generates an implicit
9+
// template for operator()
10+
// - The same generic lambda can accept arguments of different types
11+
//
12+
// Docs:
13+
// - https://en.cppreference.com/w/cpp/language/lambda
14+
// - https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp14/00-generic-lambdas.md
15+
//
16+
// Discussion Forum: http://forum.d2learn.org/category/20
17+
//
18+
// Auto-Checker:
19+
//
20+
// d2x checker generic-lambdas
21+
//
22+
23+
#include <d2x/cpp/common.hpp>
24+
#include <string>
25+
26+
int main() {
27+
28+
// 0. Simple generic lambda — identity
29+
auto identity = [](D2X_YOUR_ANSWER x) {
30+
return x;
31+
};
32+
33+
d2x_assert_eq(identity(42), 42);
34+
d2x_assert(identity(std::string("hello")) == "hello");
35+
d2x_assert_eq(identity(3.14), D2X_YOUR_ANSWER);
36+
37+
// 1. Generic lambda as comparator
38+
auto greater = [](auto a, auto b) {
39+
return D2X_YOUR_ANSWER;
40+
};
41+
42+
d2x_assert(greater(5, 3));
43+
d2x_assert(greater(2.5, 1.2));
44+
d2x_assert(greater(std::string("z"), std::string("a")));
45+
46+
// 2. Verify deduced types
47+
auto get_type_size = [](auto x) {
48+
return sizeof(D2X_YOUR_ANSWER);
49+
};
50+
51+
d2x_assert_eq(get_type_size(42), sizeof(int));
52+
d2x_assert_eq(get_type_size('c'), sizeof(char));
53+
54+
D2X_WAIT
55+
56+
return 0;
57+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// d2mcpp: https://github.com/mcpp-community/d2mcpp
2+
// license: Apache-2.0
3+
// file: dslings/en/cpp14/00-generic-lambdas-1.cpp
4+
//
5+
// Exercise: cpp14 | 00 - generic lambdas | generic lambda with STL algorithms
6+
//
7+
// Tips:
8+
// - A single generic lambda can be reused with containers of different
9+
// element types
10+
// - Captured variables retain their concrete types; only parameters use auto
11+
//
12+
// Docs:
13+
// - https://en.cppreference.com/w/cpp/language/lambda
14+
// - https://github.com/mcpp-community/d2mcpp/blob/main/book/en/src/cpp14/00-generic-lambdas.md
15+
//
16+
// Discussion Forum: http://forum.d2learn.org/category/20
17+
//
18+
// Auto-Checker:
19+
//
20+
// d2x checker generic-lambdas
21+
//
22+
23+
#include <d2x/cpp/common.hpp>
24+
#include <vector>
25+
#include <algorithm>
26+
27+
int main() {
28+
29+
// 0. Same generic lambda used to sort containers of different element types
30+
std::vector<int> v1 = {5, 1, 4, 2, 8};
31+
std::vector<double> v2 = {3.1, 2.7, 8.5, 1.9};
32+
33+
auto desc = [](D2X_YOUR_ANSWER a, D2X_YOUR_ANSWER b) {
34+
return a > b;
35+
};
36+
37+
std::sort(v1.begin(), v1.end(), desc);
38+
d2x_assert_eq(v1[0], 8);
39+
d2x_assert_eq(v1[4], 1);
40+
41+
std::sort(v2.begin(), v2.end(), desc);
42+
d2x_assert_eq(v2[0], D2X_YOUR_ANSWER);
43+
44+
// 1. Generic lambda with capture — find_if
45+
int threshold = 3;
46+
auto above = [threshold](auto x) {
47+
return x > threshold;
48+
};
49+
50+
auto it1 = std::find_if(v1.begin(), v1.end(), above);
51+
d2x_assert(*it1 == D2X_YOUR_ANSWER);
52+
53+
auto it2 = std::find_if(v2.begin(), v2.end(), above);
54+
d2x_assert(*it2 == 8.5);
55+
56+
// 2. Generic lambda returning lambda — factory function
57+
auto make_multiplier = [](auto factor) {
58+
return [factor](auto x) { return x * D2X_YOUR_ANSWER; };
59+
};
60+
61+
auto times2 = make_multiplier(2);
62+
d2x_assert_eq(times2(10), 20);
63+
d2x_assert_eq(times2(0.5), 1.0);
64+
65+
D2X_WAIT
66+
67+
return 0;
68+
}

dslings/en/cpp14/xmake.lua

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
set_languages("cxx14")
2+
3+
-- target: cpp14-00-generic-lambdas
4+
5+
target("cpp14-00-generic-lambdas-0")
6+
set_kind("binary")
7+
add_files("00-generic-lambdas-0.cpp")
8+
9+
target("cpp14-00-generic-lambdas-1")
10+
set_kind("binary")
11+
add_files("00-generic-lambdas-1.cpp")
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// d2mcpp: https://github.com/mcpp-community/d2mcpp
2+
// license: Apache-2.0
3+
// reference solution for: dslings/cpp14/00-generic-lambdas-0.cpp
4+
//
5+
// 用途: 仅给 CI 与维护者参考使用,不是教程入口。
6+
// 教程练习入口: dslings/cpp14/00-generic-lambdas-0.cpp
7+
//
8+
9+
#include <d2x/cpp/common.hpp>
10+
#include <string>
11+
12+
int main() {
13+
14+
// 0. 简单泛型 lambda — identity
15+
auto identity = [](auto x) {
16+
return x;
17+
};
18+
19+
d2x_assert_eq(identity(42), 42);
20+
d2x_assert(identity(std::string("hello")) == "hello");
21+
d2x_assert_eq(identity(3.14), 3.14);
22+
23+
// 1. 泛型 lambda 做比较
24+
auto greater = [](auto a, auto b) {
25+
return a > b;
26+
};
27+
28+
d2x_assert(greater(5, 3));
29+
d2x_assert(greater(2.5, 1.2));
30+
d2x_assert(greater(std::string("z"), std::string("a")));
31+
32+
// 2. 推导类型确认
33+
auto get_type_size = [](auto x) {
34+
return sizeof(x);
35+
};
36+
37+
d2x_assert_eq(get_type_size(42), sizeof(int));
38+
d2x_assert_eq(get_type_size('c'), sizeof(char));
39+
40+
return 0;
41+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// d2mcpp: https://github.com/mcpp-community/d2mcpp
2+
// license: Apache-2.0
3+
// reference solution for: dslings/cpp14/00-generic-lambdas-1.cpp
4+
//
5+
// 用途: 仅给 CI 与维护者参考使用,不是教程入口。
6+
// 教程练习入口: dslings/cpp14/00-generic-lambdas-1.cpp
7+
//
8+
9+
#include <d2x/cpp/common.hpp>
10+
#include <vector>
11+
#include <algorithm>
12+
13+
int main() {
14+
15+
// 0. 同一个泛型 lambda 用于不同元素类型的容器排序
16+
std::vector<int> v1 = {5, 1, 4, 2, 8};
17+
std::vector<double> v2 = {3.1, 2.7, 8.5, 1.9};
18+
19+
auto desc = [](auto a, auto b) {
20+
return a > b;
21+
};
22+
23+
std::sort(v1.begin(), v1.end(), desc);
24+
d2x_assert_eq(v1[0], 8);
25+
d2x_assert_eq(v1[4], 1);
26+
27+
std::sort(v2.begin(), v2.end(), desc);
28+
d2x_assert_eq(v2[0], 8.5);
29+
30+
// 1. 带捕获的泛型 lambda — find_if
31+
int threshold = 3;
32+
auto above = [threshold](auto x) {
33+
return x > threshold;
34+
};
35+
36+
auto it1 = std::find_if(v1.begin(), v1.end(), above);
37+
d2x_assert(*it1 == 8);
38+
39+
auto it2 = std::find_if(v2.begin(), v2.end(), above);
40+
d2x_assert(*it2 == 8.5);
41+
42+
// 2. 泛型 lambda 返回 lambda — 函数工厂
43+
auto make_multiplier = [](auto factor) {
44+
return [factor](auto x) { return x * factor; };
45+
};
46+
47+
auto times2 = make_multiplier(2);
48+
d2x_assert_eq(times2(10), 20);
49+
d2x_assert_eq(times2(0.5), 1.0);
50+
51+
return 0;
52+
}

solutions/cpp14/xmake.lua

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
set_languages("cxx14")
2+
3+
-- target: cpp14-00-generic-lambdas
4+
5+
target("cpp14-00-generic-lambdas-0-ref")
6+
set_kind("binary")
7+
add_files("00-generic-lambdas-0.cpp")
8+
9+
target("cpp14-00-generic-lambdas-1-ref")
10+
set_kind("binary")
11+
add_files("00-generic-lambdas-1.cpp")

0 commit comments

Comments
 (0)