std::variant与std::visit:从访问者模式到类型安全联合
访问者Visitor模式想解决的是有一族结构相对稳定的类型上面要挂多种易变的操作求值、打印、序列化……又不想在每个类里无限加成员函数也不想用一长串if (dynamic_cast...)。std::variant把「只能是这几种之一」写进类型系统std::visit在运行期根据当前激活的是哪一种调用访问者里对应的分支——语义上就是Visitor 分派但常常不需要公共基类和虚函数表。本文以设计模式视角串起variant/visit/monostate/ 常见坑文末用一小节点到与 CRTP 笔记 里「异构容器」话题的弱关联不是主线。1. 访问者模式在解决什么两类变化维度维度典型变化设计上的期望元素类型结构新增一种 AST 结点、一种协议消息体相对稳定或「闭集」可枚举对元素的操作新增一种 pass、一种校验、一种 dump更频繁希望集中写在一处访问者的意图把「对每种类型的操作」收拢到一个访问者对象里通过分派把「当前到底是哪种元素」与「要执行哪段逻辑」接起来经典写法里常叫二次分派。2. 经典 OO 访问者 vsvariantvisit2.1 经典写法示意每个具体元素实现accept(Visitor)内部回调visitor.visit(*this)访问者类里 overload 一组visit(const ConcreteA),visit(const ConcreteB)……优点类型开放——以后可再派生子类配合虚函数。代价继承层次、vptr、文件分散新增一种元素类型要改多个类的visit重载。2.2variantvisit闭集访问者若你能明确说元素只会是A | B | C这几种闭集可以把元素建模为std::variantA,B,Celem;对「某一种操作」写成一个可调用对象函数对象 / lambda 集交给std::visitstd::visit(my_visitor,elem);语义仍是「带着操作走遍各种具体类型」——Visitor 的形态。实现分派由标准库实现可生成跳转表等不必手写accept也不必公共基类。代价类型集写死在variantA,B,...里新增一种类型要改variant模板参数并重新编译所有visit调用点闭集的天然限制。3.std::variant基础3.1 定义与赋值#includevariant#includestring#includeiostreamstructCircle{doubler;};structRectangle{doublew,h;};intmain(){std::variantCircle,Rectangle,intv;vCircle{1.0};// 当前持有 CirclevRectangle{2,3};// 切换为 Rectanglev42;// 第三种 alternativeintstd::coutstd::holds_alternativeint(v)\n;// 1}同一时间只有一个alternative 是「激活」的。赋值会销毁旧值、构造新值可能抛异常见 §7。3.2std::monostate第一个类型不能默认构造时variant默认构造时会默认构造第一个类型。若第一个类型没有默认构造函数用std::monostate占位作为第一个模板参数structNoDefault{explicitNoDefault(int){}};usingVstd::variantstd::monostate,NoDefault,int;// V v; // 默认构造 monostate表示「尚未放置有效值」这在「先声明、后写入」的解析器、状态机里很常见。4.std::visit把「访问者」交给标准库4.1 手写访问者类C17 起即可最清晰#includevariant#includeiostreamstructCircle{doubler;};structRectangle{doublew,h;};structAreaVisitor{doubleoperator()(constCirclec)const{return3.1415926*c.r*c.r;}doubleoperator()(constRectangler)const{returnr.w*r.h;}};intmain(){std::variantCircle,RectanglevCircle{2.0};std::coutstd::visit(AreaVisitor{},v)\n;// 约 12.56}AreaVisitor就是典型的Visitor每种operator()对应一种元素类型。4.2 多variant一起 visitstd::visit可以接受多个variant访问者需要能处理笛卡尔积里每一种组合或模板化常用于「两个联合类型配对处理」// 伪代码示意visit(visitor, v1, v2);// visitor 需对 (v1 的每种) × (v2 的每种) 有对应调用 —— 组合爆炸时要谨慎设计实际工程里更常见的是visit一个variant或把多域数据放进一个struct再variant...。4.3overload惯用法C20lambda 包成一块「访问者」把多个 lambda 合成一个可调用对象省去写具名 struct#includevariant#includeiostream#includestring// C20变参继承 推导指引templateclass...Tsstructoverloaded:Ts...{usingTs::operator()...;};templateclass...Tsoverloaded(Ts...)-overloadedTs...;intmain(){std::variantint,std::stringvhello;std::visit(overloaded{[](intx){std::coutint x\n;},[](conststd::strings){std::coutstr s\n;},},v);}C17没有上述推导指引时仍推荐手写struct访问者或显式指定overloaded...的模板实参可读性往往好于强行塞宏。5. 取值与检查get/get_if/holds_alternative/indexstd::variantint,std::stringv7;if(autopstd::get_ifint(v)){std::cout*p\n;// 安全不是 int 则 p nullptr}try{autosstd::getstd::string(v);// 类型不对则抛 std::bad_variant_access}catch(conststd::bad_variant_access){// ...}switch(v.index()){// 0 int, 1 stringcase0:/* ... */break;case1:/* ... */break;}能visit就优先visit新增 alternative 时编译器会逼你补全访问者分支若用overload全覆盖。用index()switch容易漏 case或与模板参数顺序强耦合维护成本高。6. 与「虚函数 Visitor」的对照维度虚接口 经典 Visitorvariantvisit类型集开放可再派生闭集写死在variant...分派vtable标准库实现跳转表 / 链式 if 等由实现定义堆与缓存常配合unique_ptrBase对象可内联在variant存储里新增操作给 Visitor 加接口所有元素类配合accept给visit的访问者加重载 / lambda新增类型派生 实现accept 各 Visitor overload改variant模板参数 所有visit分支选型一句话闭集、值语义、少堆分配 →variantvisit要插件式扩展类型、二进制 ABI 边界 →虚函数体系更合适。7. 常见坑7.1bad_variant_access对错误的std::getT/std::getI会抛std::bad_variant_access。get_if指针版不抛。7.2valueless_by_exception若在赋值/emplace过程中抛出异常且无法保证旧值恢复variant可能进入valueless状态此时index()为variant_npos多数操作未定义行为前应检查v.valueless_by_exception()。7.3 自赋值与大型对象variant里放大对象时赋值可能触发分配/搬移热点路径可评估是否用unique_ptrT作 alternative 减拷贝成本权衡堆分配。7.4visit的可调用对象必须无歧义覆盖所有类型overload里若两个 lambda 都能匹配同一类型会编译失败与 Visitor 里重载决议规则一致。8. 与其它现代特性的组合点到为止std::optional/std::expected常和「解析结果」一起出现不要用optionalvariant...盲目套娃——有时variantMonostate, A, B或expectedvariant..., E更清晰。C26 模式匹配inspect/match若标准化落地会是visit的语法糖方向当前生产环境仍以visitoverload为主流。9. 和CRTP 笔记 的关系弱交叉非主线crtp.md 在讨论「编译期多态接不住运行期异构容器」时把variantvisit列为异构方案之一与虚函数、手写类型擦除并列。那里的重点是CRTP 解决的是另一类问题variant不是 CRTP 的「替代品」而是当你明确只有闭集类型、又想在vector里值语义存放时的一种访问者式实现路径。主线仍应是Visitor 意图 →variant建模闭集 →visit写操作。与 CRTP 的交叉保持「知道去哪延伸阅读」即可。10. 一句话总结访问者把「对多类型的操作」聚到一处通过分派连接类型与逻辑。std::variant用类型系统表达闭集联合std::visit对该联合做类型安全的多路分派。与经典虚 Visitor互补闭集 值语义优先variant开放扩展优先虚接口。优先visit而非裸index()switch更利于穷举检查与维护。记住variant回答「是哪一种」visit回答「对这一种做什么」——合在一起就是现代 C 里的访问者骨架。

相关新闻

老游戏在Windows 10/11疯狂闪退?这款免费兼容性补丁如何彻底修复游戏崩溃

老游戏在Windows 10/11疯狂闪退?这款免费兼容性补丁如何彻底修复游戏崩溃

老游戏在Windows 10/11疯狂闪退?这款免费兼容性补丁如何彻底修复游戏崩溃 【免费下载链接】SilentPatchBully SilentPatch for Bully: Scholarship Edition (fixes crashes on Windows 10) 项目地址: https://gitcode.com/gh_mirrors/si/SilentPatchBully 周…

2026/8/18 18:45:03 阅读更多 →
QML与C++交互

QML与C++交互

QML 与 C++ 的交互是 Qt Quick 开发的核心需求,常用于将界面逻辑与底层业务逻辑解耦。 一、基础交互机制 元对象系统(Meta-Object System):基于 Qt 的 moc(元对象编译器)生成反射信息,实现 QML 与 C++ 的双向通信,依赖信号槽(Signals & Slots)和属性绑定(Propert…

2026/8/18 18:45:03 阅读更多 →
TVA-World架构:在工业质检中小试牛刀(6)

TVA-World架构:在工业质检中小试牛刀(6)

前沿技术探索:TVA智能体(简称TVA)TVA智能体(亦称“AI智能体视觉”或“TVA视觉智能体”)是依托Transformer架构与“因式智能体”理论构建的系统级视觉技术框架。它融合深度强化学习(DRL)、卷积神…

2026/8/18 18:45:03 阅读更多 →

最新新闻

HTTP QUERY方法详解:复杂查询的标准化解决方案与Spring Boot实践

HTTP QUERY方法详解:复杂查询的标准化解决方案与Spring Boot实践

在 HTTP 协议的发展历程中,GET、POST、PUT、DELETE 等方法是开发者最熟悉的工具。然而,随着应用场景的复杂化,特别是对复杂查询和搜索需求的增长,传统的 GET 方法在语义和功能上开始显得力不从心。GET 方法虽然用于获取资源&#…

2026/8/18 19:55:47 阅读更多 →
DeepSeek Harness 小白入门 22:strict JSON Schema:结构更稳,但为什么仍要二次校验

DeepSeek Harness 小白入门 22:strict JSON Schema:结构更稳,但为什么仍要二次校验

DeepSeek Harness 小白入门 22:strict JSON Schema:结构更稳,但为什么仍要二次校验 [!NOTE] 这是 第二阶段 协议护栏 的第 22 课。本文面向第一次接触 Agent Harness 的读者,目标是:正确使用 strict 工具 Schema 并保留应用侧验证。真实练习场景是:让工具参数严格满足城…

2026/8/18 19:55:47 阅读更多 →
视频实时翻译神器:一键生成双语字幕,跨平台高效处理外语视频

视频实时翻译神器:一键生成双语字幕,跨平台高效处理外语视频

你是不是也遇到过这样的场景:好不容易找到一份宝贵的外语学习资料、技术讲座或者行业报告视频,结果发现没有字幕,或者字幕是外语的,看得一头雾水?手动翻译?效率太低。找在线工具?要么收费&#…

2026/8/18 19:55:47 阅读更多 →
DeepSeek Harness 小白入门 23:标准端点还是 /beta?带工具时千万别混用

DeepSeek Harness 小白入门 23:标准端点还是 /beta?带工具时千万别混用

DeepSeek Harness 小白入门 23:标准端点还是 /beta?带工具时千万别混用 [!NOTE] 这是 第二阶段 协议护栏 的第 23 课。本文面向第一次接触 Agent Harness 的读者,目标是:分清标准 Chat Completions 与 Beta 补全能力。真实练习场景是:为工具调用固定官方标准 Base URL。全…

2026/8/18 19:55:47 阅读更多 →
物业数智化落地的「红黑榜」技术解构:一份工单数据背后的系统差距

物业数智化落地的「红黑榜」技术解构:一份工单数据背后的系统差距

一、从一份评定结果看物业数智化的真实水位 2026年8月,尖草坪区物业服务企业第一批"红黑榜"如期出炉。这份评定依据是综合打分、投诉工单转办、平台受理数据和日常巡检记录——四项维度中,投诉工单转办和平台受理数据两项,直接反映…

2026/8/18 19:55:47 阅读更多 →
Weblogic+iframe解析问题

Weblogic+iframe解析问题

方法 A&#xff1a;在父页面加 <meta> 标签<head><meta http-equiv"Connection" content"close"> </head>⚠️ 这个 meta 标签会被浏览器忽略——HTTP/1.1 规范不允许用 meta 控制 Connection 头。方法 B&#xff1a;在父页面用 J…

2026/8/18 19:54:47 阅读更多 →

日新闻

告别逐帧截图:用 extract-video-ppt 快速提取视频中的 PPT 并一键导出 PDF

告别逐帧截图:用 extract-video-ppt 快速提取视频中的 PPT 并一键导出 PDF

告别逐帧截图&#xff1a;用 extract-video-ppt 快速提取视频中的 PPT 并一键导出 PDF 【免费下载链接】extract-video-ppt extract the ppt in the video 项目地址: https://gitcode.com/gh_mirrors/ex/extract-video-ppt 如果你还停留在"看网课 不停暂停 截图 …

2026/8/18 0:00:57 阅读更多 →
思源宋体TTF一站式上手:7个字重免费商用,从下载到上线的完整走查

思源宋体TTF一站式上手:7个字重免费商用,从下载到上线的完整走查

思源宋体TTF一站式上手&#xff1a;7个字重免费商用&#xff0c;从下载到上线的完整走查 【免费下载链接】source-han-serif-ttf Source Han Serif TTF 项目地址: https://gitcode.com/gh_mirrors/so/source-han-serif-ttf 你是不是也经历过这种时刻&#xff1a;设计稿里…

2026/8/18 0:00:58 阅读更多 →
华硕笔记本控制权回收指南:GHelper 如何用一个 10MB 文件替代 Armoury Crate

华硕笔记本控制权回收指南:GHelper 如何用一个 10MB 文件替代 Armoury Crate

华硕笔记本控制权回收指南&#xff1a;GHelper 如何用一个 10MB 文件替代 Armoury Crate 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, …

2026/8/18 0:00:59 阅读更多 →

周新闻

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

如果你是一名开发者&#xff0c;最近可能已经感受到了AI大模型正在从“玩具”变成“生产力工具”的强烈信号。从代码补全到智能Agent&#xff0c;从本地部署到云端API&#xff0c;我们正处在一个技术栈快速重构的节点。然而&#xff0c;面对层出不穷的模型、框架和工具&#xf…

2026/8/18 9:15:35 阅读更多 →
工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/18 9:06:28 阅读更多 →
【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。&#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室&#x1f447; 关注我领取海量matlab电子书和…

2026/8/18 9:04:56 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速&#xff1a;macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/17 18:54:37 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南&#xff1a;3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗&#xff1f;ncmdump解密工具帮你轻松解决这个困…

2026/8/17 18:55:16 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片&#xff1a;为英语学习 App 打造桌面级学习助手适用平台&#xff1a;HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0&#xff08;API 26 Beta&#xff09;新增了 AgentCard 智能体卡片能力&#xff0c;这是继 HMAF&#xff08;鸿蒙智能体框架&#x…

2026/8/17 18:55:55 阅读更多 →