std::visit 是访问 std::variant 值的强制要求,因 std::get 需编译期确定类型,否则抛 std::bad_variant_access 导致崩溃;正确做法是用 std::visit 统一分发并由编译器生成各类型的处理分支。
std::visit 是访问 std::variant 中当前持有值的唯一标准方式,不是可选技巧,而是强制要求——不通过 std::visit(或其变体如 std::holds_alternative + std::get)就无法安全取出值。
为什么不能直接用 std::get 访问 variant?
因为 std::get(v) 要求编译期确定 v 当前确实持有类型 T,否则抛出 std::bad_variant_access。而运行时类型是动态的,硬写 std::get(v) 很容易崩溃。
常见错误现象:std::terminate 被调用,控制台只显示 “terminate called after throwing an instance of ‘std::bad_variant_access’” —— 这说明你绕过了类型检查,直接强取了错误分支。
正确做法是:先用 std::visit 统一分发,让编译器为你生成所有可能类型的处理分支:
立即学习“C++免费学习笔记(深入)”;
std::variant v = 3.14;
std::visit([](const auto& x) {
using T = std::decay_t;
if constexpr (std::is_same_v) {
std::cout << "int: " << x << "\n";
} else if constexpr (std::is_same_v) {
std::cout << "string: " << x << "\n";
} else if constexpr (std::is_same_v) {
std::cout << "double: " << x << "\n";
}
}, v);
如何写一个能复用的 visitor 类?
Lambda 写多了会重复,尤其当多个地方要对同一 std::variant 做类似 dispatch 时。这时应定义具名 visitor 结构体,显式继承 std::variant 所有可选项的重载 operator():
- 必须为 variant 中每种类型都提供一个
operator()重载,否则编译失败(这是安全性的体现) - 避免使用模板
operator()单一入口,除非配合if constexpr,否则可能漏处理某类型 - 如果某些类型处理逻辑相同,可以共用一个重载,比如
void operator()(const std::string&) const和void operator()(const std::vector&) const都转成 size 输出
示例: