Skip to content

Commit d833f5b

Browse files
committed
add functional closure
1 parent 4c2d94d commit d833f5b

File tree

4 files changed

+101
-7
lines changed

4 files changed

+101
-7
lines changed

docs/functional.md

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -811,7 +811,7 @@ Lambda 函数对象的类型是匿名的,每个 Lambda 表达式都会创建
811811

812812
唯一的代价是,你需要指定出所有参数的类型,和返回值的类型。
813813

814-
例如一个参数为两个 `int` `std::function<int(int, int)>`
814+
例如参数为两个 `int`返回 `int` 的函数,可以用 `std::function<int(int, int)>` 容器存储。
815815

816816
```cpp
817817
auto add_lambda = [](int a, int b) { // Lambda 函数对象
@@ -865,10 +865,12 @@ int generic_sum(std::vector<int> const &v,
865865
866866
### 案例:函数对象的动态分发用于多线程任务队列
867867

868+
主线程不断地向工作者线程发送函数对象,令其代为执行:
869+
868870
```cpp
869871
mt_queue<std::function<void()>> task_queue;
870872

871-
void thread1() {
873+
void main_thread() {
872874
task_queue.push([] {
873875
fmt::println("正在执行任务1");
874876
});
@@ -877,7 +879,7 @@ void thread1() {
877879
});
878880
}
879881

880-
void thread2() {
882+
void worker_thread() {
881883
while (true) {
882884
auto task = task_queue.pop();
883885
task();
@@ -889,6 +891,67 @@ void thread2() {
889891
890892
### 函数对象的重要机制:闭包
891893

894+
闭包是函数对象的重要机制,他允许函数对象捕获外部变量,并在函数对象内部使用这些变量。
895+
896+
```cpp
897+
int x = 10;
898+
auto add_x = [x](int a) {
899+
return a + x;
900+
};
901+
fmt::println("{}", add_x(5)); // 输出 15
902+
```
903+
904+
闭包捕获的变量默认是只读的,如果需要修改捕获的变量,需要使用 `mutable`。
905+
906+
#### 闭包的本质是语法糖
907+
908+
Lambda 函数对象的闭包语法:
909+
910+
```cpp
911+
auto add_x = [x](int a) {
912+
return a + x;
913+
};
914+
```
915+
916+
实际上等价于一个带有 `operator()()` 的结构体:
917+
918+
```cpp
919+
struct Lambda {
920+
int x;
921+
Lambda(int val) : x(val) {}
922+
923+
int operator()(int a) {
924+
return a + x;
925+
}
926+
};
927+
928+
int main() {
929+
Lambda add_x(10);
930+
fmt::println("{}", add_x(5)); // 输出 15
931+
return 0;
932+
}
933+
```
934+
935+
而且这结构体是匿名的,没有确定的名字,此处类名 `Lambda` 只是示意。
936+
937+
**而所谓的闭包捕获变量,实际上就是这个结构体的成员!**
938+
939+
按值捕获,就相当于结构体成员里拷贝了一份同名的成员;如果是引用捕获,就相当于结构体里的成员是个引用。
940+
941+
> {{ icon.tip }} 可以在 https://cppinsights.io 这个网站,自动拆解包括 Lambda 在内的所有现代 C++ 语法糖为原始的结构体和函数。更多好用的工具网站可以看我们 [工具和项目推荐](recommend.md) 专题章节。
942+
943+
#### 闭包捕获变量的生命周期问题
944+
945+
正因如此,闭包按值捕获(`[=]`)的变量,其生命周期和 Lambda 对象相同。
946+
947+
当 Lambda 对象被拷贝时,其按值捕获的所有变量也会被重新拷贝一份。
948+
949+
当 Lambda 对象被移动时,其按值捕获的所有变量也会随之一起移动。
950+
951+
如果按值捕获了不能拷贝的对象(比如 `std::unique_ptr`),那么 Lambda 对象也会无法拷贝,只能移动。
952+
953+
#### `operator()` 很有迷惑性
954+
892955
### 函数指针是 C 语言陋习,改掉
893956

894957
## bind 为函数对象绑定参数
@@ -921,3 +984,9 @@ int main() {
921984
return 0;
922985
}
923986
```
987+
988+
### `std::placeholders`
989+
990+
### bind 是一个失败的设计
991+
992+
### `std::bind_front``std::bind_back`

docs/img/thanks.png

261 KB
Loading

docs/recommend.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
- learncpp.com
55
- cppreference.com
66
- godbolt.org
7-
- cpp-insights.io
7+
- cppinsights.io
88
- quick-bench.com
99
- github.com
1010
- stackoverflow.com

misc/afdian.py

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,25 @@ class Order(namedtuple('Order', ['remark'])):
2727
User('**振', '', '20.00', ''),
2828
User('**伟', '', '20.00', ''),
2929
User('**枫', '', '26.90', ''),
30+
User('相欢', '', '100.00', ''),
31+
User('**辉', '', '30.00', '支持一下小彭老师,嘿嘿(求匿名)'),
32+
User('**峰', '', '26.90', '感谢小鹏老师在技术上无私奉献,加油!'),
33+
User('**卿', '', '26.60', ''),
34+
User('**飞', '', '26.90', '黑心老板太可恶,资助老师吃饭�9�'),
35+
User('**宇', '', '26.90', '给小彭老师点赞'),
36+
User('**逸', '', '26.90', '绵薄之力,希望小彭老师早日度过难关'),
37+
User('**帆', '', '10.00', '祝小彭老师生活顺利'),
38+
User('**蓝', '', '500.00', '小彭老师加油�0�5�0�5'),
39+
User('*洋', '', '26.90', ''),
40+
User('**豪', '', '66.00', ''),
41+
User('**楠', '', '26.90', '小彭老师加油!凭你的才华没问题的'),
42+
User('*锷', '', '100.00', ''),
43+
User('**博', '', '30.00', '小彭老师加油,你这么优秀肯定能找到好工作'),
44+
User('**运', '', '30.00', '小彭老师加油!B站视频太棒啦!'),
45+
User('windy小助手', 'https://i0.hdslb.com/bfs/face/d5d323e4063cad911bd722292fbf67dc6a23493b.jpg', '500.00', ''),
46+
User('**康', '', '40.00', '感谢小彭老师的指导'),
47+
User('*坤', '', '40.00', ''),
48+
User('**峰', '', '20.00', ''),
3049
]
3150

3251
def afd_query(which, **params):
@@ -35,7 +54,7 @@ def afd_query(which, **params):
3554
ts = int(time.time())
3655
params = json.dumps(params)
3756
sign = hashlib.md5(f'{token}params{params}ts{ts}user_id{user_id}'.encode('utf-8')).hexdigest()
38-
res = requests.get(f'https://afdian.net/api/open/{which}', params={
57+
res = requests.get(f'https://afdian.com/api/open/{which}', params={
3958
'user_id': user_id,
4059
'params': params,
4160
'ts': ts,
@@ -86,7 +105,7 @@ def afd_gen_thank_list():
86105
max_y = 30
87106
stride_x = 450
88107
stride_y = 120
89-
limit_y = 720
108+
limit_y = stride_y * 10
90109
max_max_y = max_y
91110
for user in sponsors:
92111
max_y += stride_y
@@ -104,7 +123,8 @@ def afd_gen_thank_list():
104123
for user in sponsors:
105124
draw = ImageDraw.Draw(img)
106125
font = ImageFont.truetype('/usr/share/fonts/noto-cjk/NotoSansCJK-Medium.ttc', size=20)
107-
font_small = ImageFont.truetype('/usr/share/fonts/noto-cjk/NotoSerifCJK-Medium.ttc', size=13)
126+
font_small = ImageFont.truetype('/usr/share/fonts/noto-cjk/NotoSansCJK-Medium.ttc', size=13)
127+
# font_small = ImageFont.truetype('/usr/share/fonts/Unifont/Unifont.otf', size=13)
108128
if user.avatar:
109129
avatar = Image.open(BytesIO(requests.get(user.avatar).content))
110130
else:
@@ -121,6 +141,11 @@ def afd_gen_thank_list():
121141
remark = user.remark
122142
if remark:
123143
remark = remark.rstrip('。').replace('.。', ',')
144+
# chunk remark into 40 char per line:
145+
chunk_size = int((stride_x - 100) / font_small.size)
146+
if len(remark) > chunk_size:
147+
remark_lines = [remark[i:i+chunk_size] for i in range(0, len(remark), chunk_size)]
148+
remark = '\n'.join(remark_lines)
124149
draw.text((x + 100, y + 60), f'{remark}', fill='#779977', font=font_small)
125150
print(f'{user.name}{user.all_sum_amount} {remark}')
126151
total += float(user.all_sum_amount)

0 commit comments

Comments
 (0)