std:: visit
|
定义于头文件
<variant>
|
||
|
template
<
class
Visitor,
class
...
Variants
>
constexpr /* 见下文 */ visit ( Visitor && v, Variants && ... values ) ; |
(1) | (C++17 起) |
|
template
<
class
R,
class
Visitor,
class
...
Variants
>
constexpr R visit ( Visitor && v, Variants && ... values ) ; |
(2) | (C++20 起) |
|
辅助模板
|
||
|
template
<
class
...
Ts
>
auto && as - variant ( std:: variant < Ts... > & value ) ; |
(3) | ( 仅用于说明* ) |
|
template
<
class
...
Ts
>
auto && as - variant ( const std:: variant < Ts... > & value ) ; |
(4) | ( 仅用于说明* ) |
|
template
<
class
...
Ts
>
auto && as - variant ( std:: variant < Ts... > && value ) ; |
(5) | ( 仅用于说明* ) |
|
template
<
class
...
Ts
>
auto && as - variant ( const std:: variant < Ts... > && value ) ; |
(6) | ( 仅用于说明* ) |
将访问器 v (一个可调用对象,能够以 Variants 中类型的任意组合进行调用)应用于 Variants values 。
给定
VariantBases
为
decltype
(
as-variant
(
std::
forward
<
Variants
>
(
values
)
)
...
(一个包含
sizeof...
(
Variants
)
个类型的包):
INVOKE
(
std::
forward
<
Visitor
>
(
v
)
,
std
::
get
<
indices
>
(
std::
forward
<
VariantBases
>
(
values
)
)
...
)
,
as-variant
(
values
)
.
index
(
)
...
。
INVOKE<R>
(
std::
forward
<
Visitor
>
(
v
)
,
std
::
get
<
indices
>
(
std::
forward
<
VariantBases
>
(
values
)
)
...
)
,
as-variant
(
values
)
.
index
(
)
...
。
这些重载仅当
VariantBases
中的每个类型均为有效类型时才参与重载决议。若由
INVOKE
或
INVOKE<R>
(C++20 起)
指代的表达式无效,或
INVOKE
或
INVOKE<R>
(C++20 起)
的结果对于不同
indices
具有不同类型或值类别,则程序非良构。
as-variant
函数模板接受一个类型可被
推导
为
std::
variant
<
Ts...
>
的值(即可以是
std::
variant
<
Ts...
>
或派生自
std::
variant
<
Ts...
>
的类型),并返回具有相同常量限定符和值类别的
std::variant
值。
目录 |
参数
| v | - | 一个 Callable 对象,可接受 Variants 中所有变体的所有可能选项 |
| values | - | 要传递给访问者的变体列表 |
返回值
异常
若
as-variant
(
value_i
)
.
valueless_by_exception
(
)
对
values
中的任何变体
value_i
为
true
,则抛出
std::bad_variant_access
。
复杂度
当变体数量为零或一时,可调用对象的调用以常数时间实现;即其执行时间不取决于变体所能存储的类型数量。
如果变体数量大于一,可调用对象的调用没有复杂度要求。
注释
设
n
为
(
1
*
...
*
std::
variant_size_v
<
std::
remove_reference_t
<
VariantBases
>>
)
,实现通常为每个
std::visit
的特化生成一个等价于(可能是多维)包含
n
个函数指针的数组的表,这种实现方式与
虚函数
的实现类似。
实现也可以为
std::visit
生成具有
n
个分支的
switch 语句
(例如,当
n
不大于 256 时,MSVC STL 实现会使用 switch 语句)。
在典型实现中,调用 v 的时间复杂度可视为等同于访问(可能为多维)数组元素或执行 switch 语句的时间复杂度。
| 特性测试宏 | 值 | 标准 | 功能特性 |
|---|---|---|---|
__cpp_lib_variant
|
202102L
|
(C++23)
(DR17) |
std::visit
用于派生自
std::variant
的类
|
示例
#include <iomanip> #include <iostream> #include <string> #include <type_traits> #include <variant> #include <vector> // 要访问的 variant using value_t = std::variant<int, long, double, std::string>; // 访问器 #4 的辅助类型 template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; }; // 显式推导指南(C++20 起不再需要) template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>; int main() { std::vector<value_t> vec = {10, 15l, 1.5, "hello"}; for (auto& v: vec) { // 1. void 访问器,仅用于副作用(此处用于 I/O) std::visit([](auto&& arg){ std::cout << arg; }, v); // 2. 返回值访问器,演示返回另一个 variant 的惯用法 value_t w = std::visit([](auto&& arg) -> value_t { return arg + arg; }, v); // 3. 类型匹配访问器:为每种类型提供不同处理的 lambda std::cout << "。翻倍后,variant 持有 "; std::visit([](auto&& arg) { using T = std::decay_t<decltype(arg)>; if constexpr (std::is_same_v<T, int>) std::cout << "值为 " << arg << " 的 int\n"; else if constexpr (std::is_same_v<T, long>) std::cout << "值为 " << arg << " 的 long\n"; else if constexpr (std::is_same_v<T, double>) std::cout << "值为 " << arg << " 的 double\n"; else if constexpr (std::is_same_v<T, std::string>) std::cout << "值为 " << std::quoted(arg) << " 的 std::string\n"; else static_assert(false, "非穷举访问器!"); }, w); } for (auto& v: vec) { // 4. 另一个类型匹配访问器:包含 3 个重载 operator() 的类 // 注意:`(auto arg)` 模板 operator() 在此情况下将绑定到 `int` 和 `long`, // 但若缺少它,`(double arg)` operator() *也会* 绑定到 `int` 和 `long`, // 因为两者均可隐式转换为 double。使用此形式时,需注意隐式转换的正确处理。 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。翻倍后,variant 持有值为 20 的 int 15。翻倍后,variant 持有值为 30 的 long 1.5。翻倍后,variant 持有值为 3 的 double hello。翻倍后,variant 持有值为 "hellohello" 的 std::string 10 15 1.500000 "hello"
缺陷报告
下列行为变更缺陷报告被追溯应用于先前发布的 C++ 标准。
| 缺陷报告 | 适用范围 | 发布时行为 | 正确行为 |
|---|---|---|---|
| LWG 2970 | C++17 |
重载版本
(1)
的返回类型未保留
INVOKE
操作结果的值类别
|
保留值类别 |
|
LWG 3052
( P2162R2 ) |
C++17 |
当
Variants
中存在非
std::variant
类型时行为未作规定 |
已作明确规定 |
参见
|
(C++26)
|
以
variant
持有的参数调用提供的函数对象
(公开成员函数) |
与另一个
variant
交换内容
(公开成员函数) |