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 ( Callable , который может быть вызван с любой комбинацией типов из 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 | - | a Callable который принимает любую возможную альтернативу из каждого варианта в Variants |
| values | - | список вариантов для передачи посетителю |
Возвращаемое значение
R
является (возможно, с cv-квалификаторами)
void
; иначе результат операции
INVOKE<R>
.
Исключения
Выбрасывает
std::bad_variant_access
если
as-variant
(
value_i
)
.
valueless_by_exception
(
)
равно
true
для любого варианта
value_i
в
values
.
Сложность
Когда количество вариантов равно нулю или одному, вызов вызываемого объекта реализуется за постоянное время; т.е. оно не зависит от количества типов, которые могут храниться в варианте.
Если количество вариантов больше одного, вызов вызываемого объекта не имеет требований к сложности.
Примечания
Пусть
n
будет
(
1
*
...
*
std::
variant_size_v
<
std::
remove_reference_t
<
VariantBases
>>
)
, реализации обычно генерируют таблицу, эквивалентную (возможно, многомерному) массиву из
n
указателей на функции для каждой специализации
std::visit
, что аналогично реализации
виртуальных функций
.
Реализации также могут генерировать
switch statement
с
n
ветвями для
std::visit
(например, реализация MSVC STL использует switch statement, когда
n
не превышает 256).
В типичных реализациях временная сложность вызова 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> // вариант для посещения 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, "привет"}; for (auto& v: vec) { // 1. void visitor, вызывается только для side-effects (здесь, для I/O) std::visit([](auto&& arg){ std::cout << arg; }, v); // 2. возвращающий значение посетитель, демонстрирует идиому возврата другого варианта value_t w = std::visit([](auto&& arg) -> value_t { return arg + arg; }, v); // 3. посетитель с сопоставлением типов: лямбда, которая обрабатывает каждый тип по-разному std::cout << ". После удвоения вариант содержит "; std::visit([](auto&& arg) { using T = std::decay_t<decltype(arg)>; if constexpr (std::is_same_v<T, int>) std::cout << "int со значением " << arg << '\n'; else if constexpr (std::is_same_v<T, long>) std::cout << "long со значением " << arg << '\n'; else if constexpr (std::is_same_v<T, double>) std::cout << "double со значением " << arg << '\n'; else if constexpr (std::is_same_v<T, std::string>) std::cout << "std::string со значением " << std::quoted (Примечание: Согласно требованиям, HTML-теги и атрибуты не переведены, термин `std::quoted` как специфический для C++ оставлен без перевода)(arg) << '\n'; else static_assert(false, "неполный посетитель!"); }, w); } for (auto& v: vec) { // 4. другой тип-матчинговый посетитель: класс с 3 перегруженными operator() // Примечание: Шаблонный оператор `(auto arg)` будет привязываться к `int` и `long` // в данном случае, но при его отсутствии оператор `(double arg)` operator() // *также* будет связываться с `int` и `long`, поскольку оба неявно // convertible to double. При использовании этой формы необходимо соблюдать осторожность // что неявные преобразования обрабатываются корректно. std::visit(overloaded{ [](auto arg) { std::cout << arg << ' '; }, [](double arg) { std::cout << std::fixed << arg << ' '; }, [](const std::string& arg) { std::cout << std::quoted (Примечание: Согласно требованиям, HTML-теги и атрибуты не переведены, термин `std::quoted` как специфический для C++ оставлен без перевода)(arg) << ' '; } }, v); } }
Вывод:
10. После удвоения, variant содержит int со значением 20 15. После удвоения, variant содержит long со значением 30 1.5. После удвоения, variant содержит double со значением 3 hello. После удвоения, variant содержит std::string со значением "hellohello" 10 15 1.500000 "hello"
Отчеты о дефектах
Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Applied to | Behavior as published | Correct behavior |
|---|---|---|---|
| LWG 2970 | C++17 |
the return type of overload
(1)
did not preserve the
value category of the result of the
INVOKE
operation
|
preserves |
|
LWG 3052
( P2162R2 ) |
C++17 |
the effects were unspecified if any type
in
Variants
is not a
std::variant
|
specified |
Смотрите также
|
(C++26)
|
вызывает предоставленный функтор с аргументом, содержащимся в
variant
(публичная функция-член) |
обменивается содержимым с другим
variant
(публичная функция-член) |