< cpp‎ | utility‎ | variant
Utilities library
General utilities
Date and time
Function objects
Formatting library (C++20)
Relational operators (deprecated in C++20)
Integer comparison functions
Swap and type operations
Common vocabulary types

Elementary string conversions
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

Effectively returns

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

, where is... is 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.


[edit] Parameters

vis - a Callable that accepts every possible alternative from every variant
vars - list of variants to pass to the visitor

[edit] 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.

[edit] Exceptions

Throws std::bad_variant_access if any variant in vars is valueless_by_exception.

[edit] 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.

[edit] 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';
                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
        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"

[edit] See also

swaps with another variant
(public member function) [edit]