std::visit
处理 variant 的备选类型
std::visit 是 CoddyKit 上的免费 C++ Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C++ Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C++ Academy 课程共包含 4 节课。
为何使用 std::visit?
使用 get_if 手动检查每个备选类型会变得冗长。std::visit 会将可调用对象应用于 variant 当前保存的类型,并替您处理分派。
#include <iostream>
#include <variant>
int main() {
std::variant<int, double> v = 4;
std::visit([](auto x){ std::cout << x << "\n"; }, v);
}通用 Lambda 访问器
如果函数体对所有备选类型都能编译通过,那么接收 auto 的 lambda 就适用于每一种备选类型。在这里,我们会打印当前活动的类型。
#include <iostream>
#include <string>
#include <variant>
int main() {
std::variant<int, std::string> v = std::string("hi");
std::visit([](const auto& x){ std::cout << x << "\n"; }, v);
}返回一个值
std::visit 可以返回一个值。每个分支都必须返回相同的类型。
#include <iostream>
#include <variant>
int main() {
std::variant<int, double> v = 2.5;
double d = std::visit([](auto x){ return x * 2.0; }, v);
std::cout << d << "\n";
}使用 if constexpr 实现按类型处理
要在一个通用 lambda 中针对不同类型执行不同操作,请将 if constexpr 与 std::decay_t 和 std::is_same_v 结合使用。
#include <iostream>
#include <string>
#include <variant>
#include <type_traits>
int main() {
std::variant<int, std::string> v = 5;
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 std::cout << "str " << x << "\n";
}, v);
}结构体访问器
您也可以编写一个包含多个 operator() 重载的结构体,每种类型对应一个重载。编译器会选择匹配的重载。
#include <iostream>
#include <string>
#include <variant>
struct Printer {
void operator()(int i) const { std::cout << "int " << i << "\n"; }
void operator()(const std::string& s) const { std::cout << "str " << s << "\n"; }
};
int main() {
std::variant<int, std::string> v = std::string("yo");
std::visit(Printer{}, v);
}overloaded 惯用法
一种常用的辅助工具可以将多个 lambda 组合成一个访问器。每个 lambda 负责处理一种特定类型。
#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> v = 8;
std::visit(overloaded{
[](int i){ std::cout << "i=" << i << "\n"; },
[](const std::string& s){ std::cout << "s=" << s << "\n"; }
}, v);
}完备性
访问器必须处理每一个备选类型,否则代码将无法编译。这项编译期检查可以防止遗漏某种情况。
访问并修改
如果您以非常量引用传递 variant,访问器就可以直接修改其中保存的值。
#include <iostream>
#include <variant>
int main() {
std::variant<int, double> v = 10;
std::visit([](auto& x){ x += 1; }, v);
std::cout << std::get<int>(v) << "\n";
}多个 Variant
std::visit 可以同时接收多个 variant;访问器随后会针对每个 variant 接收一个参数。
#include <iostream>
#include <variant>
int main() {
std::variant<int, double> a = 2;
std::variant<int, double> b = 3.0;
auto sum = std::visit([](auto x, auto y){ return x + y; }, a, b);
std::cout << sum << "\n";
}选择访问器风格
对于统一处理,请使用通用的 auto lambda;对于清晰的按类型逻辑,请使用 overloaded 惯用法;当行为需要在多个调用位置复用时,请使用结构体访问器。
Visit 与 get_if
对于单次快速检查,get_if 已经够用;但 std::visit 更具扩展性:它强制要求覆盖所有备选类型,并将所有按类型处理的逻辑集中在一个位置。
快速检查
请检查您对 std::visit 的理解。
回顾
您学习了std::visit:
- 将可调用对象分派给活动的备选类型。
- 可以使用通用 lambda、
if constexpr、结构体访问器或 overloaded 惯用法。 - 访问器必须覆盖所有备选类型(编译期检查)。
- 可以返回值,也可以同时访问多个 variant。
常见问题解答
「std::visit」课时是免费的吗?
是的 — 「std::visit」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C++ Academy 课程的其余内容,请升级到 CoddyKit PRO。 C++ Academy 课程共包含 4 节课。
「std::visit」这节课中我会学到什么?
处理 variant 的备选类型 你通过在浏览器中直接运行的动手代码来练习 C++ Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 C++ Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 C++ Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「std::visit」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 C++ Academy 课中编写并运行代码吗?
能。每节 C++ Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 带作用域的 enum class
- 联合体及其风险
- std::variant
- std::visit