讲师中心 微信公众号
AI工具推荐 视频效率加速

C++中std::visit与std::variant怎么配合使用_C++17多态替代方案【设计】

落杰酱_3848

落杰酱_3848

发布时间:2026-02-06 16:02:32

|

808人浏览过

|

来源于php中文网

原创

std::visit 是访问 std::variant 值的强制要求,因 std::get 需编译期确定类型,否则抛 std::bad_variant_access 导致崩溃;正确做法是用 std::visit 统一分发并由编译器生成各类型的处理分支。

c++中std::visit与std::variant怎么配合使用_c++17多态替代方案【设计】

std::visit 是访问 std::variant 中当前持有值的唯一标准方式,不是可选技巧,而是强制要求——不通过 std::visit(或其变体如 std::holds_alternative + std::get)就无法安全取出值。

为什么不能直接用 std::get 访问 variant?

因为 std::get<t>(v)</t> 要求编译期确定 v 当前确实持有类型 T,否则抛出 std::bad_variant_access。而运行时类型是动态的,硬写 std::get<int>(v)</int> 很容易崩溃。

常见错误现象:std::terminate 被调用,控制台只显示 “terminate called after throwing an instance of 'std::bad_variant_access'” —— 这说明你绕过了类型检查,直接强取了错误分支。

正确做法是:先用 std::visit 统一分发,让编译器为你生成所有可能类型的处理分支:

立即学习“C++免费学习笔记(深入)”;

std::variant<int, std::string, double> v = 3.14;
std::visit([](const auto& x) {
    using T = std::decay_t<decltype(x)>;
    if constexpr (std::is_same_v<T, int>) {
        std::cout << "int: " << x << "\n";
    } else if constexpr (std::is_same_v<T, std::string>) {
        std::cout << "string: " << x << "\n";
    } else if constexpr (std::is_same_v<T, double>) {
        std::cout << "double: " << x << "\n";
    }
}, v);

如何写一个能复用的 visitor 类?

Lambda 写多了会重复,尤其当多个地方要对同一 std::variant 做类似 dispatch 时。这时应定义具名 visitor 结构体,显式继承 std::variant 所有可选项的重载 operator():

Web Accessibility (WCAG 2 AA))
Web Accessibility (WCAG 2 AA))

将 WCAG 2 AA 无障碍标准应用于设计系统、UI 组件和网页——通过可运行的验证器进行对比度计算,采用设计 token 模式使颜色天生可访问,设定排版和焦点状态规则,并提供语义检查清单。适用于构建或审查 UI。

下载
  • 必须为 variant 中每种类型都提供一个 operator() 重载,否则编译失败(这是安全性的体现)
  • 避免使用模板 operator() 单一入口,除非配合 if constexpr,否则可能漏处理某类型
  • 如果某些类型处理逻辑相同,可以共用一个重载,比如 void operator()(const std::string&) const 和 void operator()(const std::vector<char>&) const</char> 都转成 size 输出

示例:

struct Printer {
    void operator()(int i) const { std::cout << "int=" << i; }
    void operator()(const std::string& s) const { std::cout << "str=" << s; }
    void operator()(double d) const { std::cout << "dbl=" << d; }
};
// 使用
std::variant<int, std::string, double> v = "hello";
std::visit(Printer{}, v); // 输出 str=hello

std::visit 的异常安全性与性能影响

std::visit 本身不抛异常(除非你 visitor 里主动 throw),但它内部会做一次运行时分支判断(通常编译为查表或条件跳转),开销极小,远低于虚函数调用或 dynamic_cast —— 因为 variant 的 type index 是内建存储的,无需 RTTI 查找。

注意两个易忽略点:

  • 如果 variant 是空状态(std::monostate 或 move 后未赋值),std::visit 仍会尝试调用 visitor,但不会匹配任何重载,导致编译失败;所以建议 variant 至少包含 std::monostate 作为默认项,并为其提供 operator()
  • visitor 对象若含状态(比如捕获外部变量的 lambda),需确认其生命周期覆盖 visit 调用;临时 lambda 没问题,但局部 struct 引用外部栈变量就危险

替代虚函数多态时的关键设计权衡

用 std::variant + std::visit 替代基类指针/引用 + 虚函数,本质是从“运行时开放扩展”转向“编译期封闭枚举”。这意味着:

  • 新增类型需修改 variant 定义、所有 visitor 实现、所有 switch-like 分支 —— 不适合插件化或未知子类场景
  • 没有对象生命周期管理开销(不用 new/delete,无虚表指针,缓存友好)
  • 编译器更容易内联 visitor 中的每个分支,实际性能常优于虚调用
  • 无法实现“向上转型”或“动态添加行为”,比如不能把 std::variant<a></a> 隐式转成 std::variant<a></a>

所以它不是万能多态替代品,而是当你明确知道所有可能类型、且追求零成本抽象时的精准工具。

最常被忽略的是:variant 的“类型集合”一旦固定,就锁死了整个访问契约。改一个类型,所有 visitor 都得同步更新——这既是约束,也是文档。

热门AI工具

更多
DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

音述AI
音述AI Hot

一款AI音频处理工具,主要用于音述AI是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区,适合需要提升相关任务效率的用户。

蛙蛙写作

一款AI论文写作工具,主要用于超级AI智能写作助手,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

花生AI
花生AI Hot

一款AI视频创作工具,主要用于B站推出的AI视频创作工具,适合需要提升相关任务效率的用户。

VibeKnow
VibeKnow Hot

一款AI视频创作工具,主要用于全球首个AI知识视频创作平台,文档、文章、网页,一键生成视频,适合需要提升相关任务效率的用户。

创客贴AI

创客贴AI是一款AI图像与设计工具,AI辅助的智能在线设计工具。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

6859

2023.08.02

switch语句用法
switch语句用法

switch语句用法:1、Switch语句只能用于整数类型,枚举类型和String类型,不能用于浮点数类型和布尔类型;2、每个case语句后面必须跟着一个break语句,以防止执行其他case的代码块,没有break语句,将会继续执行下一个case的代码块;3、可以在一个case语句中匹配多个值,使用逗号分隔;4、Switch语句中的default代码块是可选的等等。

1071

2023.09.21

Java switch的用法
Java switch的用法

Java中的switch语句用于根据不同的条件执行不同的代码块。想了解更多switch的相关内容,可以阅读本专题下面的文章。

1437

2024.03.13

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

355

2025.11.27

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

355

2025.11.27

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

2318

2023.09.20

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

5014

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

5171

2025.07.04

Vite 项目如何打包和部署
Vite 项目如何打包和部署

Vite项目打包部署专题汇集生产构建、产物预览、输出目录、资源路径、Nginx与GitHub Pages部署及常见白屏和路由404问题的已审核文章,帮助读者完成上线流程。

60

2026.10.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
SQL 教程
SQL 教程

共61课时 | 7.5万人学习

C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn