跳转到内容
主菜单
主菜单
移至侧栏
隐藏
导航
首页
最近更改
随机页面
MediaWiki帮助
代码酷
搜索
搜索
中文(中国大陆)
外观
创建账号
登录
个人工具
创建账号
登录
未登录编辑者的页面
了解详情
贡献
讨论
编辑“︁
C++17stdvariant
”︁(章节)
页面
讨论
大陆简体
阅读
编辑
编辑源代码
查看历史
工具
工具
移至侧栏
隐藏
操作
阅读
编辑
编辑源代码
查看历史
常规
链入页面
相关更改
特殊页面
页面信息
外观
移至侧栏
隐藏
您的更改会在有权核准的用户核准后向读者展示。
警告:
您没有登录。如果您进行任何编辑,您的IP地址会公开展示。如果您
登录
或
创建账号
,您的编辑会以您的用户名署名,此外还有其他益处。
反垃圾检查。
不要
加入这个!
= C++17 std::variant = '''std::variant''' 是 C++17 标准库中引入的一个模板类,用于表示一个类型安全的联合体(union)。它可以存储一组预定义类型中的某一个值,并在运行时安全地访问该值,避免了传统 C 风格联合体(union)的类型不安全问题。std::variant 是 C++ 中实现多态的一种方式,尤其适用于需要存储多种可能类型但每次只使用其中一种的场景。 == 基本介绍 == std::variant 类似于一个类型安全的联合体,它允许你在一个变量中存储多种不同类型的值,但在任何时候只能存储其中的一种。它提供了一种比 C 风格联合体更安全、更现代的方式来处理多类型数据。 === 主要特点 === * '''类型安全''':std::variant 在编译时检查类型,避免运行时错误。 * '''可访问性检查''':可以通过 std::holds_alternative 或 std::visit 安全地访问存储的值。 * '''异常安全''':如果访问错误的类型,会抛出 std::bad_variant_access 异常(除非使用 std::get_if)。 * '''默认构造''':默认构造时存储第一个类型的默认值(如果第一个类型是可默认构造的)。 == 基本用法 == === 定义与初始化 === std::variant 定义时需要指定可能的类型列表。例如: <syntaxhighlight lang="cpp"> #include <variant> #include <string> #include <iostream> int main() { // 定义一个可以存储 int、double 或 std::string 的 variant std::variant<int, double, std::string> v; v = 42; // 存储 int std::cout << "Stored int: " << std::get<int>(v) << "\n"; v = 3.14; // 存储 double std::cout << "Stored double: " << std::get<double>(v) << "\n"; v = "Hello"; // 存储 std::string std::cout << "Stored string: " << std::get<std::string>(v) << "\n"; return 0; } </syntaxhighlight> '''输出:''' <pre> Stored int: 42 Stored double: 3.14 Stored string: Hello </pre> === 访问值 === 有几种方式可以访问 std::variant 中存储的值: 1. '''std::get''':直接获取特定类型的值(如果类型不匹配会抛出异常) <syntaxhighlight lang="cpp"> try { auto s = std::get<std::string>(v); // 正确 auto i = std::get<int>(v); // 抛出 std::bad_variant_access } catch (const std::bad_variant_access& e) { std::cerr << "Error: " << e.what() << "\n"; } </syntaxhighlight> 2. '''std::get_if''':安全地获取指针(如果类型不匹配返回 nullptr) <syntaxhighlight lang="cpp"> if (auto p = std::get_if<int>(&v)) { std::cout << "Got int: " << *p << "\n"; } else { std::cout << "Not storing int\n"; } </syntaxhighlight> 3. '''std::holds_alternative''':检查是否存储特定类型 <syntaxhighlight lang="cpp"> if (std::holds_alternative<double>(v)) { std::cout << "Storing a double\n"; } </syntaxhighlight> 4. '''std::visit''':使用访问者模式处理所有可能类型 <syntaxhighlight lang="cpp"> struct Visitor { void operator()(int i) { std::cout << "int: " << i << "\n"; } void operator()(double d) { std::cout << "double: " << d << "\n"; } void operator()(const std::string& s) { std::cout << "string: " << s << "\n"; } }; std::visit(Visitor{}, v); // 根据当前存储的类型调用相应的 operator() </syntaxhighlight> == 实际应用案例 == === 配置系统 === 在配置系统中,一个配置项可能是多种类型之一: <syntaxhighlight lang="cpp"> struct ConfigItem { std::string name; std::variant<int, bool, std::string> value; }; void printConfig(const ConfigItem& item) { std::cout << item.name << ": "; std::visit([](auto&& arg) { std::cout << arg; }, item.value); std::cout << "\n"; } int main() { ConfigItem items[] = { {"Timeout", 30}, {"DebugMode", true}, {"Username", "admin"} }; for (const auto& item : items) { printConfig(item); } return 0; } </syntaxhighlight> '''输出:''' <pre> Timeout: 30 DebugMode: 1 Username: admin </pre> === 解析JSON或XML === 在处理JSON或XML数据时,一个节点值可能是多种类型: <syntaxhighlight lang="cpp"> using JsonValue = std::variant<std::nullptr_t, bool, int, double, std::string>; void processJsonValue(const JsonValue& value) { std::visit([](auto&& arg) { using T = std::decay_t<decltype(arg)>; if constexpr (std::is_same_v<T, std::nullptr_t>) { std::cout << "null"; } else if constexpr (std::is_same_v<T, bool>) { std::cout << (arg ? "true" : "false"); } else { std::cout << arg; } }, value); } </syntaxhighlight> == 状态图示例 == 以下是 std::variant 的状态转换图: <mermaid> stateDiagram [*] --> Empty Empty --> HoldsType1: assign Type1 Empty --> HoldsType2: assign Type2 HoldsType1 --> HoldsType2: assign Type2 HoldsType2 --> HoldsType1: assign Type1 HoldsType1 --> [*]: destroy HoldsType2 --> [*]: destroy </mermaid> == 与联合体(union)的比较 == {| class="wikitable" |- ! 特性 !! std::variant !! C风格union |- | 类型安全 || 是 || 否 |- | 知道当前存储的类型 || 是 || 否 |- | 支持非POD类型 || 是 || 否 |- | 异常安全 || 是 || 否 |- | 内存占用 || 可能稍大 || 最小 |} == 性能考虑 == * std::variant 通常比 C 风格 union 使用更多内存,因为它需要存储类型信息 * 访问操作(特别是 std::visit)可能比直接访问变量稍慢 * 对于性能关键代码,应考虑基准测试 == 数学表示 == 从数学上看,std::variant 可以表示为类型系统的和类型(sum type): <math> \text{variant}(T_1, T_2, ..., T_n) = T_1 + T_2 + ... + T_n </math> == 总结 == std::variant 是 C++17 中引入的强大特性,它提供了一种类型安全的方式来处理多类型数据。相比传统的联合体,它更安全、更灵活,特别适合需要存储多种可能类型但每次只使用其中一种的场景。通过 std::visit 等工具,可以优雅地处理所有可能的类型情况。 [[Category:编程语言]] [[Category:C++]] [[Category:C++141720 特性]]
摘要:
请注意,所有对代码酷的贡献均被视为依照知识共享署名-非商业性使用-相同方式共享发表(详情请见
代码酷:著作权
)。如果您不希望您的文字作品被随意编辑和分发传播,请不要在此提交。
您同时也向我们承诺,您提交的内容为您自己所创作,或是复制自公共领域或类似自由来源。
未经许可,请勿提交受著作权保护的作品!
取消
编辑帮助
(在新窗口中打开)