std::visit
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> constexpr R visit( Visitor&& vis, Variants&&... vars ); |
(2) | (since C++20) |
Applies the visitor vis
(Callable that can be called with any combination of types from variants) to the variants vars
.
Every type in std::remove_reference_t<Variants>... may be a (possibly const-qualified) specialization of std::variant. It is unspecified whether other argument types, e.g. a class derived from a std::variant, are supported. Effectively returns std::invoke(std::forward<Visitor>(vis), , where |
(until C++23) |
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 Effectively returns std::invoke(std::forward<Visitor>(vis), , where every type in |
(since C++23) |
R
. If R
is (possibly cv-qualified) void, the result of the invoke
expression is discarded.Contents |
Parameters
vis | - | a Callable that accepts every possible alternative from every variant |
vars | - | list of variants to pass to the visitor |
Return value
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() || ...). |
(since C++23) |
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
#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"
See also
swaps with another variant (public member function) |