Difference between revisions of "cpp/utility/variant/visit"
(P2162R2) |
m |
||
Line 24: | Line 24: | ||
std::get<is>(std::forward<Variants>(vars))...)}} | std::get<is>(std::forward<Variants>(vars))...)}} | ||
− | , where {{tt|is...}} is {{c|vars.index()...}}. | + | , where {{tt|is...}} is {{c|vars.index()...}}. |
|since2=c++23|rev2= | |since2=c++23|rev2= | ||
− | {{cpp/enable_if|plural=yes|every type in {{c|std::remove_reference_t<Variants>...}} is a (possibly const-qualified) specialization of {{lc|std::variant}}, or a (possibly const-qualified) class {{tt|C}} such that there is exactly one {{lc|std::variant}} specialization that is a | + | {{cpp/enable_if|plural=yes|every type in {{c|std::remove_reference_t<Variants>...}} is a (possibly const-qualified) specialization of {{lc|std::variant}}, or a (possibly const-qualified) class {{tt|C}} such that there is exactly one {{lc|std::variant}} specialization that is a base class of {{tt|C}} and it is a public and unambiguous base class}}. |
Effectively returns | Effectively returns | ||
Line 33: | Line 33: | ||
std::get<is>(std::forward<VariantBases>(vars))...)}} | std::get<is>(std::forward<VariantBases>(vars))...)}} | ||
− | , where every type in {{tt|VariantBases...}} is the unique {{lc|std::variant}} specialization determined above, except that {{c|const}}, {{c|&}}, or {{c|&&}} is added to it if the corresponding argument is of a const-qualified type, is an lvalue, or is an rvalue, respectively, and {{tt|is...}} is {{c|std::forward<VariantBases>(vars).index()...}}. | + | , where every type in {{tt|VariantBases...}} is the unique {{lc|std::variant}} specialization determined above, except that {{c|const}}, {{c|&}}, or {{c|&&}} is added to it if the corresponding argument is of a const-qualified type, is an lvalue, or is an rvalue, respectively, and {{tt|is...}} is {{c|std::forward<VariantBases>(vars).index()...}}. |
}} | }} | ||
Revision as of 19:59, 27 February 2021
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.
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 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) |