C++ 参考手册

位置:首页 > C++ 参考手册 >工具库 >std::variant > std::visit

定义于头文件 <variant>
template <class Visitor, class... Variants>
constexpr /*see below*/ visit(Visitor&& vis, Variants&&... vars);
(1) (C++17 起)
template <class R, class Visitor, class... Variants>
constexpr R visit(Visitor&& vis, Variants&&... vars);
(2) (C++20 起)

应用观览器 visvariant 变量组 vars

等效于返回

std::invoke(std::forward<Visitor>(vis), std::get<is>(std::forward<Variants>(vars))...)

,其中 is...vars.index()...

1) 如同用 decltype 从返回的表达式推导返回类型。若上述调用不是对于所有 variant 的所有可选项类型均为同一类型和值类别的合法表达式,则调用为谬构。
2) 返回类型为 R 。若 R 是(可有 cv 限定的) void ,则舍弃 invoke 表达式的结果。

参数

vis - 接受每个 variant 的每个可能可选项的可调用 (Callable) 对象
vars - 传递给观览器的 variant 列表

返回值

1) 观览器的所选调用所返回的值,转换成所有可行的 std::invoke 表达式的共用类型。
2)R 为(可有 cv 限定的) void 则为无;否则为选择的观览器调用所返回的值,再隐式转换成 R

异常

若任何 vars 中的 variant 为因异常无值( valueless_by_exception ),则抛出 std::bad_variant_access

复杂度

variant 的数量为零或一时,可调用对象的调用在常数时间内实现,即它不取决于 sizeof...(Types)

variant 的数量大于 1 ,则可调用对象的调用没有复杂度要求。

示例

#include <iomanip>
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>
 
 
template<class T> struct always_false : std::false_type {};
 
using var_t = std::variant<int, long, double, std::string>;
 
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>; // C++20 起不需要
 
int main() {
    std::vector<var_t> vec = {10, 15l, 1.5, "hello"};
    for(auto&& v: vec) {
        // void 观览器,仅为其副效应调用
        std::visit([](auto&& arg){std::cout << arg;}, v);
 
        // 返回值的观览器,返回另一 variant 的常见模式
        var_t w = std::visit([](auto&& arg) -> var_t {return arg + arg;}, v);
 
        std::cout << ". After doubling, variant holds ";
        // 类型匹配观览器:亦能为带 4 个重载的 operator() 的类
        std::visit([](auto&& arg) {
            using T = std::decay_t<decltype(arg)>;
            if constexpr (std::is_same_v<T, int>)
                std::cout << "int with value " << arg << '\n';
            else if constexpr (std::is_same_v<T, long>)
                std::cout << "long with value " << arg << '\n';
            else if constexpr (std::is_same_v<T, double>)
                std::cout << "double with value " << arg << '\n';
            else if constexpr (std::is_same_v<T, std::string>)
                std::cout << "std::string with value " << std::quoted(arg) << '\n';
            else 
                static_assert(always_false<T>::value, "non-exhaustive visitor!");
        }, w);
    }
 
    for (auto&& v: vec) {
        std::visit(overloaded {
            [](auto arg) { std::cout << arg << ' '; },
            [](double arg) { std::cout << std::fixed << arg << ' '; },
            [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; },
        }, v);
    }
}

输出:

10. After doubling, variant holds int with value 20
15. After doubling, variant holds long with value 30
1.5. After doubling, variant holds double with value 3
hello. After doubling, variant holds std::string with value "hellohello"
10 15 1.500000 "hello"

参阅

与另一 variant 交换
(公开成员函数)