0Pricing
C++ Academy · 课时

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 反馈 — 无需本地设置。

此课程中的所有课时

  1. 带作用域的 enum class
  2. 联合体及其风险
  3. std::variant
  4. std::visit
← 返回 C++ Academy