如何在C++中使用std::variant实现类型安全的多态容器

在 C++17 标准以后,std::variant 提供了一种轻量级的、类型安全的多态容器。它可以在运行时存放若干种不同类型的值,并且编译器会在编译期帮助你检查类型。相比传统的基类指针和 void*std::variant 更安全、可读性更高。本文将从基本用法、访问方式、访问者模式、以及常见问题四个部分,系统介绍如何使用 std::variant 构建一个类型安全的多态容器。

1. 基本声明与初始化

#include <variant>
#include <string>
#include <iostream>

using MyVariant = std::variant<int, double, std::string>;

上述定义创建了一个名为 MyVariant 的别名,它可以保存 intdoublestd::string 三种类型中的任意一种。下面展示几种不同的初始化方式:

MyVariant v1 = 42;                     // int
MyVariant v2 = 3.14;                   // double
MyVariant v3 = std::string("hello");   // std::string

若想显式指定所需的类型索引,可以使用 std::variant 的构造函数:

MyVariant v4( std::in_place_index <2>, "world" ); // 位置索引为 2,对应 std::string

2. 访问与查询

2.1 std::getstd::get_if

最直接的访问方式是 std::get,它要求你确定当前存放的是哪种类型,否则会抛出 std::bad_variant_access

int i = std::get <int>(v1);   // 成功
// int j = std::get <double>(v1);  // 运行时异常

如果不确定类型,可以使用 std::get_if,它返回一个指针,若类型不匹配则返回 nullptr

if (auto p = std::get_if<std::string>(&v3)) {
    std::cout << "string: " << *p << '\n';
}

2.2 indexholds_alternative

v.index() 返回当前类型在类型列表中的索引(从 0 开始)。
`std::holds_alternative

(v)` 判断当前值是否为类型 `T`。 “`cpp if (v2.index() == 1) { std::cout (v3)) { std::cout ; if constexpr (std::is_same_v) { std::cout ) { std::cout ) { std::cout >` 结合 `has_value()` 与 `operator bool()` 使用即可。 | ## 5. 实战示例:简易表达式求值器 下面给出一个利用 `std::variant` 组合实现的简易算术表达式求值器示例,演示如何构造树结构、访问、以及递归求值。 “`cpp #include #include #include #include #include struct Expr; // 前向声明 using ExprPtr = std::unique_ptr ; using Operand = std::variant; struct Expr { // 只支持二元加法 Operand left; Operand right; char op; // 仅支持 ‘+’ }; int eval(const Operand& op) { return std::visit([](auto&& arg){ using T = std::decay_t; if constexpr (std::is_same_v) { return arg; } else { // T is ExprPtr const Expr& e = *arg; int l = eval(e.left); int r = eval(e.right); return l + r; } }, op); } int main() { // 表达式 (3 + (4 + 5)) ExprPtr inner = std::make_unique (); inner->left = 4; inner->right = 5; inner->op = ‘+’; Expr root; root.left = 3; root.right = std::move(inner); root.op = ‘+’; std::cout

发表评论