C++ std::variant 与 std::visit:安全保存多种类型,写清每个处理分支

C++ std::variant 与 std::visit:安全保存多种类型,写清每个处理分支

一个配置值可能是整数,也可能是字符串;一条消息可能是登录请求,也可能是退出通知。如果候选类型在编译期已知,C++17 的 std::variant 能用一个类型安全的对象表达"这些类型中的一个",不必自己维护 union 和类型标记。

1. 先判断,再按类型取值

cpp 复制代码
#include <iostream>
#include <string>
#include <variant>

int main() {
    std::variant<int, std::string> value = std::string("ready");
    if (auto text = std::get_if<std::string>(&value)) {
        std::cout << *text << std::endl;
    }
    value = 42; // 切换到整数分支
    if (std::holds_alternative<int>(value)) {
        std::cout << std::get<int>(value) << std::endl;
    }
}

get_if 接收 variant 指针,当前类型不匹配时返回空指针,适合条件分支。get 在类型不匹配时会抛出 std::bad_variant_access。按类型访问时,该类型必须在候选列表中恰好出现一次。

从 get_if 得到的指针是在借用内部对象。如果 variant 被销毁,或切换类型导致原对象销毁,就不能再继续使用旧指针。

2. std::visit:把每种类型的处理放在一起

下面是独立的 C++17 程序。Overloaded 把多个 lambda 的调用运算符合到一个访问器中,让不同类型走不同分支。

cpp 复制代码
#include <iostream>
#include <string>
#include <variant>

template<class... Ts>
struct Overloaded : Ts... {
    using Ts::operator()...;
};
template<class... Ts>
Overloaded(Ts...) -> Overloaded<Ts...>;

int main() {
    std::variant<int, std::string> value = std::string("ready");
    std::visit(Overloaded{
        [](int number) {
            std::cout << "number: " << number << std::endl;
        },
        [](const std::string& text) {
            std::cout << "text: " << text << std::endl;
        }
    }, value);
}

访问器必须能处理所有可能的分支。上面两个分支都返回 void。C++17 中常用的 std::visit 调用还要求各分支返回类型和值类别一致;一个返回 int、另一个返回 string,不能直接当成同一种返回结果。

3. 默认值不等于"没有值"

variant 默认构造时会默认构造第一个候选类型;例如以 int 为第一个类型时,通常得到整数零,而不是空状态。若需要显式表示"尚未设置",可以把 std::monostate 放在第一位:

cpp 复制代码
std::variant<std::monostate, int, std::string> config;
// 默认处于 monostate 分支;此处是示意片段,需要相应头文件

给它写 visit 时,也要处理 monostate。另一个需要知道的边界是:某些切换类型操作在构造抛异常时,variant 可能进入 valueless_by_exception 状态。它与主动设计的 monostate 不一样;对这种无值状态调用 visit 会抛出 bad_variant_access。

4. 速查

需求 推荐接口
判断当前类型 holds_alternative
类型匹配就取得指针 get_if
明确知道类型并接受异常检查 get
统一处理所有类型 visit
需要业务上的"未设置" 增加 monostate 分支

variant 适合有限、已知的候选类型集合。把每种状态的处理规则写完整,比散落的类型判断和强制转换更容易维护。

相关推荐
WJ.Polar18 小时前
Java封装、继承、多态
java·开发语言
摇滚侠18 小时前
Java 中如何表示负数,有符号和无符号的区别,补码的计算规则,char byte short int long 的范围
java·开发语言
weixin_3077791318 小时前
C++代码实现MATLAB中的fitrtree函数功能
开发语言·c++·算法·matlab
AI wins18 小时前
c++新增頭文件
c++
Shadow(⊙o⊙)18 小时前
仿muduo实现高并发服务器——事件就绪管理Channel.hpp
服务器·c++
爱读书的小胖18 小时前
Codewars:Rot13(C)解题分析
c语言·开发语言
鸽鸽程序猿18 小时前
【项目】【在线判题系统】b端题目增删改
开发语言·python
by2099918 小时前
哈希表——快速找到数据:冲突、删除与扩容的实现
数据结构·c++·哈希算法·散列表
Lhappy嘻嘻18 小时前
读懂 JVM:内存模型、类加载机制、分代回收
java·开发语言·jvm
音草19 小时前
C++ 继承详解:从概念到菱形继承
c++