table of contents
std::visit(3) | C++ Standard Libary | std::visit(3) |
NAME¶
std::visit - std::visit
Synopsis¶
Defined in header <variant>
template <class Visitor, class... Variants>
constexpr /*see below*/ visit( Visitor&& vis, Variants&&...
vars (1) (since C++17)
);
template <class R, class Visitor, class... Variants> (2)
(since C++20)
constexpr R visit( Visitor&& vis, Variants&&... vars );
Applies the visitor vis (Callable that can be called with any combination of
types
from variants) to the variants vars.
These overloads participate in overload resolution only if every type in
std::remove_reference_t<Variants>... is a (possibly const-qualified)
specialization
of std::variant, or a (possibly const-qualified) class C such that there is
exactly
one std::variant specialization that is a base class of C and it is a public
and
unambiguous base class.
Effectively returns
std::invoke(std::forward<Visitor>(vis),
std::get<is>(std::forward<VariantBases>(vars))...)
, where every type in VariantBases... is the unique std::variant
specialization
determined above, except that const, &, or && is added to it if
the corresponding
argument is of a const-qualified type, is an lvalue, or is an rvalue,
respectively,
and is... is std::forward<VariantBases>(vars).index()....
1) The return type is deduced from the returned expression as if by decltype.
The
call is ill-formed if the invocation above is not a valid expression of the
same
type and value category, for all combinations of alternative types of all
variants.
2) The return type is R. If R is (possibly cv-qualified) void, the result of
the
invoke expression is discarded.
If R is a reference type and the implicit conversion from the result of the
std::invoke call would bind the returned reference to a temporary object, the
program is ill-formed.
(since C++23)
Parameters¶
vis - a Callable that accepts every possible alternative from
every variant
vars - list of variants to pass to the visitor
Return value¶
1) The value returned by the selected invocation of the visitor.
2) Nothing if R is (possibly cv-qualified) void; otherwise the value returned
by the
selected invocation of the visitor, implicitly converted to R.
Exceptions¶
Throws std::bad_variant_access if any variant in vars is
valueless_by_exception.
Whether any variant is valueless by exception is determined as if by
(std::forward<VariantBases>(vars).valueless_by_exception() || ...).
Complexity¶
When the number of variants is zero or one, the invocation of the
callable object is
implemented in constant time, i.e. it does not depend on
sizeof...(Types).
If the number of variants is larger than 1, the invocation of the callable
object
has no complexity requirements.
Notes¶
Let n be (1 * ... *
std::variant_size_v<std::remove_reference_t<VariantBases>>),
implementations usually generate a table equivalent to an (possibly
multidimensional) array of n function pointers for every specialization of
std::visit, which is similar to the implementation of virtual functions.
Implementations may also generate a switch statement with n branches for
std::visit
(e.g. the MSVC STL implementation uses a switch statement when n is not
greater than
256).
On typical implementations, the time complexity of the invocation of vis can
be
considered equal to that of access to an element in an (possibly
multidimensional)
array or execution of a switch statement.
Example¶
// Run this code
#include <iomanip>
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>
// the variant to visit
using var_t = std::variant<int, long, double, std::string>;
// helper constant for the visitor #3
template<class> inline constexpr bool always_false_v = false;
// helper type for the visitor #4
template<class... Ts> struct overloaded : Ts... { using
Ts::operator()...; };
// explicit deduction guide (not needed as of C++20)
template<class... Ts> overloaded(Ts...) ->
overloaded<Ts...>;
int main() {
std::vector<var_t> vec = {10, 15l, 1.5, "hello"};
for(auto& v: vec) {
// 1. void visitor, only called for side-effects (here, for I/O)
std::visit([](auto&& arg){std::cout << arg;}, v);
// 2. value-returning visitor, demonstrates the idiom of returning another
variant
var_t w = std::visit([](auto&& arg) -> var_t {return arg + arg;},
v);
// 3. type-matching visitor: a lambda that handles each type differently
std::cout << ". After doubling, variant holds ";
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_v<T>, "non-exhaustive visitor!");
}, w);
}
for (auto& v: vec) {
// 4. another type-matching visitor: a class with 3 overloaded operator()'s
// Note: The `(auto arg)` template operator() will bind to `int` and `long`
// in this case, but in its absence the `(double arg)` operator()
// *will also* bind to `int` and `long` because both are implicitly
// convertible to double. When using this form, care has to be taken
// that implicit conversions are handled correctly.
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);
}
}
Output:¶
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"
Defect reports
The following behavior-changing defect reports were applied retroactively to
previously published C++ standards.
DR Applied to Behavior as published Correct behavior
LWG 3052 C++17 the effects were unspecified if any type in specified
Variants is not a std::variant
See also¶
swap swaps with another variant
(public member function)
2022.07.31 | http://cppreference.com |