惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cyberwarzone
Cyberwarzone
Recent Announcements
Recent Announcements
D
DataBreaches.Net
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
博客园 - 聂微东
博客园 - 【当耐特】
aimingoo的专栏
aimingoo的专栏
N
Netflix TechBlog - Medium
V
Visual Studio Blog
The GitHub Blog
The GitHub Blog
Blog — PlanetScale
Blog — PlanetScale
Engineering at Meta
Engineering at Meta
L
LangChain Blog
The Cloudflare Blog
Y
Y Combinator Blog
AI
AI
P
Palo Alto Networks Blog
美团技术团队
有赞技术团队
有赞技术团队
I
Intezer
Last Week in AI
Last Week in AI
Know Your Adversary
Know Your Adversary
D
Darknet – Hacking Tools, Hacker News & Cyber Security
NISL@THU
NISL@THU
博客园 - 三生石上(FineUI控件)
MongoDB | Blog
MongoDB | Blog
S
Schneier on Security
IT之家
IT之家
博客园 - 司徒正美
A
Arctic Wolf
罗磊的独立博客
雷峰网
雷峰网
Vercel News
Vercel News
SecWiki News
SecWiki News
AWS News Blog
AWS News Blog
GbyAI
GbyAI
WordPress大学
WordPress大学
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
T
Tor Project blog
V
Vulnerabilities – Threatpost
Hugging Face - Blog
Hugging Face - Blog
H
Heimdal Security Blog
Schneier on Security
Schneier on Security
H
Help Net Security
T
Troy Hunt's Blog
N
News and Events Feed by Topic
爱范儿
爱范儿
V2EX - 技术
V2EX - 技术
Project Zero
Project Zero
T
The Exploit Database - CXSecurity.com

Bing's Blog

git-cm:在终端里用 LLM 生成 commit message Token Tracker - 追踪 Coding Agent 的 Token 使用情况 AI Coding 工具的实践经验 2025年终总结 行车记录仪视频拼接 生成文章摘要 DMA拼接 Base64压缩 2024年终总结 二维数据可视化工具-painter 对ToB和ToC的感受 轻量级参数解析库-tiny_cmdline C++标签派发技术
C++闭包二
bing · 2024-09-11 · via Bing's Blog

“多年以前"写过一篇关于C++闭包的文章,现在看来基本是关于lambda的介绍。随着经验的增加,对闭包的理解更加深刻。在上一篇文章中,介绍了我编写的一个tiny_cmdline库,随后我对一些tiny库更感兴趣,便想着做了一个集合,取名为tinylib,其中有一个tiny库是关于match的。调用方式如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
  using namespace tiny_utility;
  auto match_op = match(
      "1" | [](const auto &i) { ASSERT_EQ(i, "1"); },                              // no line break
      "2" | [](const auto &i) { ASSERT_EQ(i, "2"); },                              // no line break
      "3" | [](const auto &i) { ASSERT_EQ(i, "3"); },                              // no line break
      std::set<std::string>{"5", "6"} | [](const auto &i) { ASSERT_NE(i, "4"); },  // no line break
      placeholder | [](const auto &i) { ASSERT_TRUE(false); }                      // no line break
  );
  // for (const auto &key : std::vector<std::string>{"1", "2", "3", "4" , "5", "6"}) {
  for (const auto &key : std::vector<std::string>{"1", "2", "3", "5", "6"}) {
    match_op(key);
  }

考虑到case key的各种类型兼容,目前的match类是运行时构建的,并且是一个模板类(key的类型是各种各样的)。

如果在实际使用中,比如有某个query接口,是不会考虑在query接口中频繁构建match类的,一般会在构造或者其他初始化接口中构造一次,然后在query接口中多次调用。

但是针对match构造一次的情况,如何保存呢?不可能考虑在类的成员变量中写一长串的类型,并且这样也不适合match的扩展。

用闭包可以解决这问题,闭包的一个特点是可以隐藏一些局部变量:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// query.h

class Query {
    // ...
    std::function<void(const std::string &)> match_op_;
};

// query.cpp
#include "tiny_match.h"

Query::Query() {
    auto match_op = match(
        "1" | [](const auto &i) { ASSERT_EQ(i, "1"); },                              // no line break
        "2" | [](const auto &i) { ASSERT_EQ(i, "2"); },                              // no line break
        "3" | [](const auto &i) { ASSERT_EQ(i, "3"); },                              // no line break
        std::set<std::string>{"5", "6"} | [](const auto &i) { ASSERT_NE(i, "4"); },  // no line break
        placeholder | [](const auto &i) { ASSERT_TRUE(false); }                      // no line break
    );
    match_op_ = [match_op](const std::string &key) { match_op(key); };
}

这样,Query类通过保存一个闭包函数,避免在类中声明可变长参数的match类型。

并且,也能发现可以在query.h声明文件中,隐藏tiny_match.h的头文件,只需要在query.cpp中包含即可。

tiny_match.h的实现在: https://github.com/caibingcheng/tinylib/blob/master/tiny_utility/tiny_match.h


根据match这个案例, 再来理解闭包这个概念:

  1. 可以捕获上层函数的局部变量, 比如match_op_捕获了match_op
  2. 可以隐藏局部变量, 比如match_op, 外部通过某些接口访问match_op_时, 是无法感知match_op的存在的
  3. 通过2, 闭包可以隐藏实现细节
  4. 一个"神奇"的通道, 外部接口居然可以访问到内部的局部变量, 尽管是这个局部变量的复制体