设计 Hical OpenAPI 模块的心得

设计 Hical OpenAPI 模块的心得 一、为什么要做这件事 Hical 框架从一开始就内建了两套反射基础设施:MetaJson(DTO 字段反射)和 MetaRoutes(路由反射)。这意味着框架在编译期就已经知道"每个结构体有哪些字段、叫什么名字、什么类型、是否必填"以及"每个 Handler 有哪些路由、什么方法、什么路径"。 这些信息恰好是生成 OpenAPI spec 所需要的全部输入。 在 C++ Web 框架领域,Drogon 通过插件支持 Swagger,Oat++ 有内建的 API 文档生成,但没有任何 C++ 框架能做到"从 C++20 宏反射层自动导出 OpenAPI 3.0 spec"这件事。这是 Hical 反射层设计的一个天然延伸,也是最有潜力的差异化卖点。 做之前我最担心的问题是:C++20 的宏回退路径能不能提取足够的类型信息来生成 JSON Schema?C++26 的 jsonSchema<T>() 可以用 std::meta::type_of(member) 直接获取字段类型,但 C++20 只有 FieldDescriptor<Class, FieldType> 的成员指针。后来发现,通过 decltype(std::declval<T>().*(field.pointer)) 在 fold expression 的每次展开中推导出具体的 FieldType,完全可以做到。这个验证结果让我决定动手。 二、架构决策 四层分离 最终的架构是四层设计: 1 2 3 4 Layer 4: OpenApiEndpoint.h — serveOpenApi() / Swagger UI Layer 3: OpenApiDocument.h/cpp — 文档组装 Layer 2: OpenApiRegistry.h/cpp — 路由元数据收集 + 标注宏 Layer 1: OpenApiSchema.h — JSON Schema 生成 这不是一开始就想好的。最初的想法是把所有东西塞进一个 OpenApi.h 里——Schema 生成、路由收集、文档组装、端点注册全放一起。但很快发现几个问题: ...

April 30, 2026 · 3 min · 533 words

C++26 前瞻心得:下一代 C++ 最值得期待的特性

C++26 前瞻心得:下一代 C++ 最值得期待的特性 C++11 让 C++ 进入现代,C++20 让 C++ 追上时代,C++26 要让 C++ 重新定义「零开销抽象」的边界。 写在前面 C++26 标准预计 2026 年底正式发布。截至本文写作时(2026 年 5 月),核心特性已基本锁定,部分编译器开始提供实验性支持。 这篇文章不追求完整列举所有提案,只聊我认为对实际项目冲击最大的特性——尤其从游戏服务器和 Hical 框架开发的角度。这是 C++17 心得 和 C++20 心得 的续篇。 声明:部分特性的最终语法可能随标准定稿而调整,代码示例基于当前最新提案。 一、静态反射(Static Reflection)—— C++ 的 Game Changer 1.1 为什么反射是最重要的 C++26 特性 在 Java、C#、Go 中习以为常的操作——遍历结构体字段、获取类名、自动序列化——在 C++ 中一直只能靠宏或代码生成。C++26 的反射(P2996)让编译器在编译期暴露类型的元信息: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <meta> struct Player { uint64_t id; std::string name; int level; int64_t gold; }; // 编译期遍历所有成员 template <typename T> void printFields(const T& obj) { template for (constexpr auto member : std::meta::members_of(^T)) { if constexpr (std::meta::is_nonstatic_data_member(member)) { std::println(" {}: {}", std::meta::name_of(member), obj.[:member:]); } } } Player p{1001, "Hical", 85, 999999}; printFields(p); // 输出: // id: 1001 // name: Hical // level: 85 // gold: 999999 零运行时开销,不需要宏,不需要代码生成工具,编译器原生支持。 ...

April 21, 2026 · 8 min · 1554 words

Boost.JSON 学习课程:JSON 序列化与反序列化

课程导航:学习路径 | Boost.System | Boost.Asio | Boost.Beast | Boost.JSON | Boost.MySQL 前置知识 课程 1: Boost.System(error_code 用于安全解析) C++ 基础:模板、if constexpr、可变参数模板 JSON 数据格式基础 学习目标 完成本课程后,你将能够: 掌握 Boost.JSON 的值类型体系(value/object/array) 安全解析和序列化 JSON 数据 理解 PMR 分配器如何加速 JSON 操作 读懂 Hical 的 MetaJson 反射层——自动 JSON 序列化的实现原理 目录 前置知识 学习目标 目录 1. 核心概念 1.1 Boost.JSON vs 其他 JSON 库 1.2 值类型体系 1.3 构造与访问 2. 基础用法 2.1 创建 JSON 值 2.2 解析 JSON 字符串 2.3 序列化为字符串 2.4 访问和修改 2.5 类型转换 3. 进阶主题 3.1 PMR 分配器集成 3.2 增量解析 3.3 tag_invoke 自定义序列化 3.4 错误处理 4. Hical 实战解读 4.1 HttpRequest::jsonBody() 4.2 HttpResponse::setJsonBody() 4.3 HttpResponse::json() 工厂 4.4 MetaJson.h:反射驱动的自动序列化 4.5 PMR 与 JSON 的协同 5. 练习题 练习 1:JSON 解析与提取 练习 2:HICAL_JSON 宏实战 练习 3:安全 JSON 验证器 练习 4:PMR 性能对比 练习 5(挑战):扩展 valueToJson 参考答案 练习 1 参考答案:JSON 解析与提取 练习 2 参考答案:HICAL_JSON 宏实战 练习 3 参考答案:安全 JSON 验证器 练习 4 参考答案:PMR 性能对比 练习 5 参考答案:扩展 valueToJson 支持 optional 6. 总结与拓展阅读 C++ 类型 ↔ JSON 类型映射表 API 速查表 拓展阅读 课程回顾 1. 核心概念 1.1 Boost.JSON vs 其他 JSON 库 特性 Boost.JSON nlohmann::json RapidJSON simdjson 接口风格 Boost 风格 STL 风格 SAX/DOM 只读 PMR 支持 原生 无 自定义 Allocator 无 增量解析 stream_parser 无 SAX API 无 编译速度 快(header-only 可选) 慢 快 快 可变性 读写 读写 读写 只读 Boost 集成 天然 独立 独立 独立 Hical 选择 Boost.JSON 的原因: ...

April 15, 2026 · 18 min · 3645 words

C++26 反射落地实战:双路线条件编译实现自动路由注册、JSON 序列化与 OpenAPI 文档生成

C++26 反射落地实战:双路线条件编译实现自动路由注册、JSON 序列化与 OpenAPI 文档生成 本文以 Hical 框架(v2.5)为例,展示如何在 C++26 反射尚未被主流编译器完全支持的现阶段,用"C++26 反射 + C++20 宏回退"的双路线策略,让用户享受相同的 API——从 JSON 序列化、路由注册到 OpenAPI 3.0 文档自动生成。 问题:Web 框架中的重复样板代码 每个 Web 框架都有三大类重复劳动: 1. 路由注册——每个处理函数都要手写一行注册: 1 2 3 4 5 6 router.get("/api/users", listUsers); router.get("/api/users/{id}", getUser); router.post("/api/users", createUser); router.put("/api/users/{id}", updateUser); router.del("/api/users/{id}", deleteUser); // ... 50 个路由 = 50 行手写注册 2. JSON 序列化——每个 DTO 都要手写字段映射: 1 2 3 4 json["name"] = user.name; json["age"] = user.age; json["email"] = user.email; // ... 10 个字段 = 10 行手写映射 3. API 文档——每个接口都要手写 OpenAPI 描述,且与代码脱节: ...

April 12, 2026 · 8 min · 1516 words

深入学习 C++26 静态反射(Static Reflection)

深入学习 C++26 静态反射(Static Reflection) 提案:P2996R9(Reflection for C++26) 头文件:<meta> 命名空间:std::meta 编译器支持:Clang(P2996 实验分支)、EDG(部分)/ GCC 和 MSVC 计划中 注意:C++26 标准预计 2026 年底定稿,本文语法基于当前最新提案,最终可能有微调 一、为什么需要静态反射? 1.1 C++ 元编程的历史痛点 C++ 一直以"零开销抽象"著称,但在类型自省这件事上,四十年来只能靠旁门左道: 方案 A:宏暴力展开 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // 用宏定义可序列化结构体 #define DEFINE_FIELDS(TYPE, ...) \ static constexpr auto fields() { \ return std::make_tuple(__VA_ARGS__); \ } struct Player { uint64_t id; std::string name; int level; int64_t gold; DEFINE_FIELDS(Player, FIELD(id), FIELD(name), FIELD(level), FIELD(gold) // 手动列举每个字段 ) }; 方案 B:代码生成工具(protobuf / flatbuffers / 自研工具) ...

April 9, 2026 · 27 min · 5613 words