现代 C++ 实战(16):GoogleTest 单元测试
C++ 编译器能抓住类型错误,却抓不住「divide(10, 0) 该不该抛异常」「阶乘边界算对没有」——这些只能靠跑起来验证。第 15 篇 的工厂、策略可以测;本篇用 GoogleTest 把测试写进工程:TEST、Fixture、参数化、Mock、CMake 集成。 demo:ref/cpp_demo/basics/testing_demo/。 这是「现代 C++ 实战」系列的第 16 篇。建议先读 第 15 篇:现代设计模式。 一、为什么 C++ 更需要测试? 编译期能抓住 编译期抓不住 类型不匹配、未声明标识符 除零、越界、错误算法 部分 constexpr 逻辑 多线程竞态、资源泄漏 Concepts 约束 API 契约(返回值、异常) 重构 第 14 篇 线程池、第 08 篇 错误处理时,回归测试是安全网。GoogleTest(gtest)+ GoogleMock(gmock)是 C++ 生态事实标准。 二、GoogleTest 基础:TEST 与断言123456#include <gtest/gtest.h>TEST(Cal...
大模型数学速成(01):张量、维度与「列 = token」
你在文档里看到 [768, 1024],第一反应可能是:768 是行还是列?1024 是 token 数还是特征维?PyTorch 教程写 [batch, seq, hidden],推理引擎源码写 [n_embd, n_tokens]——同一套数据,括号顺序不同,读错维度后面所有公式都会对不上。 这一篇只解决一件事:在本系列采用的约定下,张量形状怎么读、矩阵图怎么画、常见运算后维度怎么变。 搞懂它,后面矩阵乘法、Q/K/V 投影才有共同语言。 这是「大模型数学速成」系列的第 1 篇。建议先读 第 00 篇:读 Transformer 前需要哪些数学?。下一篇我们讲 矩阵乘法——神经网络的「基本变换器」。 一、什么是张量?在深度学习里,张量(tensor) 就是存放数字的多维数组。维度越高,结构越丰富,但读法有统一套路: 维度 生活类比 大模型中的例子 1D 向量 一行成绩:[语文, 数学, 英语, …] 某一个 token 的 768 维 embedding 2D 矩阵 Excel 表格 [n_embd, n_tokens] 整段序列的...
现代 C++ 实战(15):现代设计模式
GoF 23 种设计模式在教科书上往往是一页页继承树。现代 C++ 里很多模式可以大幅瘦身:std::function 替代策略接口、make_unique 管工厂、variant + visit 做访问者——少写类,多写意图。 这一篇对应 demo:ref/cpp_demo/basics/design_patterns/(Strategy、Observer、Builder、Singleton、Command、Visitor)。 这是「现代 C++ 实战」系列的第 15 篇。建议先读 第 14 篇:线程池与背压控制。 一、模式还要学吗? 传统痛点 现代 C++ 的解 每种策略一个子类 std::function + lambda Observer 抽象接口 + 虚函数 回调列表;对象观察者用 weak_ptr 复杂构造参数爆炸 Builder 链式 + 移动语义 new/delete 散落 make_unique 工厂 + RAII 为每种类型写 Visitor 子类 std::variant + std::visit(C++17) ...
大模型数学速成(00):读 Transformer 前需要哪些数学?
你可能已经读过「Attention Is All You Need」的科普版,知道 Transformer 靠「注意力」连接 token;也可能看过 LLM 是「预测下一个词」的接龙游戏。但一旦打开技术文章或论文,公式里突然出现 $QK^\top$、LayerNorm、RoPE、KV Cache——矩阵维度对不上、符号各说各话,读几段就想关掉页面。 这一篇不讲任何具体公式,只回答一件事:接下来 11 篇数学速成,各自解决什么困惑、该怎么读。 把它当成进入 Transformer 计算世界的地图。 这是「大模型数学速成」系列的第 0 篇。本系列与「现代 C++ 实战」并行日更:同一天还会有一篇 C++ 文章,两线互不干扰。下一篇我们从最基础的约定说起——张量、维度,以及为什么「列 = token」。 一、为什么需要这个系列?「小白讲 AI」系列刻意零公式:用图书馆、接龙、投票来类比 Transformer 和 LLM,降低入门门槛。那套讲法足够建立直觉,但不足以回答下面这类问题: 困惑 典型场景 $Q \cdot K^\top$ 到底在算什么? 读论文...
现代 C++ 实战(14):线程池与背压控制
第 13 篇讲了 jthread、semaphore、latch/barrier——都是同步工具。生产环境里更常见的问题是:任务来得比处理快,线程该复用还是现开?队列该无限长还是限流?队列满了怎么办? 这一篇用 demo ref/cpp_demo/concurrency/thread_pool/ 讲线程池架构、有界队列、背压策略,以及 future/promise 取异步结果;附带 HTTP REST Server/Client 实战。 这是「现代 C++ 实战」系列的第 14 篇。建议先读 第 13 篇:C++20 同步原语。 一、为什么需要线程池?每来一个任务就 std::thread(...).detach(): 问题 后果 创建开销 线程栈分配、内核调度——毫秒级,短任务不划算 线程数爆炸 1 万并发 → 1 万线程,内存与上下文切换拖垮系统 难以复用 无法统一限流、监控、优雅关闭 线程池:固定 N 个工作线程 + 任务队列,提交方只 submit,worker 循环取任务执行——摊薄创建成本、控制并发上限。 ...
现代 C++ 实战(13):C++20 同步原语
第 12 篇用 thread、mutex、condition_variable 搭好了并发地基。C++20 补上最后几块拼图:jthread 自动 join 与协作式取消、semaphore 限流、latch / barrier 多线程阶段同步——写法更短、语义更清晰。 这一篇对应 demo:ref/cpp_demo/concurrency/sync_primitives/。 这是「现代 C++ 实战」系列的第 13 篇。建议先读 第 12 篇:多线程基础。 一、C++20 补上了什么? 原语 解决的问题 std::jthread 忘记 join() 导致 terminate;需要优雅停止后台线程 std::counting_semaphore 限制同时访问资源的线程数(连接池、限流) std::latch 一次性「等所有人到齐」 std::barrier 可重复的多阶段同步点 std::stop_token 协作式取消(配合 jthread) 编译要求:GCC 10+、Clang 10+、MSVC 2019+,-std=c++20...
现代 C++ 实战(12):多线程基础
第一季讲完语言特性,第二季进入并发与工程。第一课是 C++11 起就有的四件套:std::thread、mutex、condition_variable、atomic——创建并行任务、保护共享数据、线程间等待通知、无锁计数。 这一篇对应 demo:ref/cpp_demo/concurrency/thread_demos/(含 thread 基础、mutex、条件变量、atomic、线程安全队列)。 这是「现代 C++ 实战」系列的第 12 篇,第二季开篇。建议先读 第 11 篇:Concepts。 一、为什么需要多线程? 利用多核:CPU 密集型任务拆到多个核并行 重叠 I/O 与计算:一个线程等磁盘/网络,另一个继续算 响应性:UI 线程不阻塞于后台任务 C++ 标准库从 C++11 起提供跨平台线程抽象,不必直接写 pthread(Linux)或 Win32 API。 二、std::thread:创建、join、detach1234567891011121314151617#include <thread>#include <...
现代 C++ 实战(11):Concepts 与模板进阶
模板很强大,但约束不足时编译错误像天书——SFINAE、enable_if 能解决问题,却难写难读。C++20 Concepts 把「类型必须满足什么」写进签名,错误从 100 行模板展开变成 3 行人话。 这一篇从 SFINAE 回顾到 Concepts 语法,并配合 type_traits 与 demo:ref/cpp_demo/basics/type_traits_demo/。 这是「现代 C++ 实战」系列的第 11 篇。建议先读 第 10 篇:Ranges。 一、模板的问题:约束写在哪?12345template<typename T>T add(T a, T b) { return a + b; }add(1, 2); // OKadd("hello", "world"); // 可能编译过,但语义不对(指针相加) 我们希望:在模板实例化前就拒绝不合法的类型,并给出清晰错误——而不是在深层实例化里爆炸。 历史上三条路线: 时代 手段 C++11 SFINA...
实战进阶:用 MCP 打造多工具 Agent
上一篇我们手写了一个”单机游戏”式的 Agent——工具是自己定义的、能力是固定的,就像一个只能在自家小区逛的孩子。今天我们要让它”联网”——通过 MCP 协议接入外部工具生态,瞬间获得读写文件、查询数据库、操作 GitHub 等成千上万种能力。就像游戏角色走出新手村,接入了整个世界地图,可以接任务、买装备、组队打副本。 这是「小白讲 AI」系列的第 20 篇,也是 Agent 系列的最终章。从第 5 篇的一条 Prompt,到今天用 MCP 打造多工具 Agent——我们走了一段不短的路。这一篇既是实战教程,也是对整个系列的总结和回顾。 一、上一篇的 Agent 缺什么?回顾一下第 19 篇手写的研究助手 Agent——它能跑,但有几个明显的限制: 工具是硬编码的:只有 search 和 fetch_url 两个工具,想加新工具就得改代码 不能操作本地文件:Agent 查到了信息却没法保存下来 单打独斗:只有一个 Agent 在干活,没有分工协作 代码量随复杂度增长:工具越多、逻辑越复杂,手写代码越难维护 今天我们要解决这些问题: 用 MCP 让 Agent 动态...
动手构建你的第一个 Agent:从零到"能自己干活"
前面 6 篇文章,我们学了发动机原理(Loop)、车架设计(Harness)、接口标准(MCP)、零件品牌对比(框架)、建筑规范(设计模式)。你已经了解了 Agent 的方方面面——但你从来没有亲手造过一个。今天,我们开箱,把零件一个个组装起来,让一个 Agent 真正跑起来。不用任何框架,纯 Python 手写,你会亲眼看到前面讲的每一个概念在代码中是怎么工作的。 这是「小白讲 AI」系列的第 19 篇。第 12 篇我们学了怎么调用 AI API(单次对话)。这一篇我们要在那个基础上,把”单次对话”升级成”自主循环”——让 AI 不只是回答你一次,而是自己持续工作直到任务完成。 一、我们要造什么?今天的目标是构建一个 “研究助手 Agent”——你给它一个研究问题,它会: 自主搜索互联网上的相关信息 阅读搜索结果中的关键内容 整理信息并生成一份结构化的研究报告 全程自主决策,你不需要一步步指导它 比如你问:”2026 年最流行的 AI Agent 框架有哪些?”它会自己去搜索、阅读、比较、整理,最后给你一份有条有理的报告。 我们不使用任何框架——所有代码都是手写的。...















