std::visit
| Definiert in der Header-Datei <variant> |
||
| template< class Visitor, class... Variants > constexpr /* siehe unten */ visit( Visitor&& v, Variants&&... values ); |
(1) | (seit C++17) |
| template< class R, class Visitor, class... Variants > constexpr R visit( Visitor&& v, Variants&&... values ); |
(2) | (seit C++20) |
| Hilfsschablonen |
||
| template< class... Ts > auto&& as-variant( std::variant<Ts...>& value ); |
(3) | (nur Exposition*) |
| template< class... Ts > auto&& as-variant( const std::variant<Ts...>& value ); |
(4) | (nur Exposition*) |
| template< class... Ts > auto&& as-variant( std::variant<Ts...>&& value ); |
(5) | (nur Exposition*) |
| template< class... Ts > auto&& as-variant( const std::variant<Ts...>&& value ); |
(6) | (nur Exposition*) |
Wendet den Visitor v (ein Callable, der mit jeder Kombination von Typen aus Variants aufgerufen werden kann) auf die Varianten values an.
Sei VariantBases decltype(as-variant(std::forward<Variants>(values))... (ein Pack von sizeof...(Variants) Typen)
INVOKE(std::forward<Visitor>(v),
std::get<indices>(std::forward<VariantBases>(values))...),
INVOKE<R>(std::forward<Visitor>(v),
std::get<indices>(std::forward<VariantBases>(values))...),
Diese Überladungen nehmen nur an der Überladungsauflösung teil, wenn jeder Typ in VariantBases ein gültiger Typ ist. Wenn der durch INVOKE oder INVOKE<R>(seit C++20) bezeichnete Ausdruck ungültig ist oder die Ergebnisse von INVOKE oder INVOKE<R>(seit C++20) für verschiedene indices unterschiedliche Typen oder Wertkategorien aufweisen, ist das Programm ill-formed.
as-variant akzeptieren einen Wert, dessen Typ für std::variant<Ts...> deduziert werden kann (d.h. entweder std::variant<Ts...> oder ein von std::variant<Ts...> abgeleiteter Typ) und geben den std::variant-Wert mit derselben Const-Qualifikation und Wertkategorie zurück.Inhalt |
[edit] Parameter
| v | - | Ein Callable, der jede mögliche Alternative aus jeder Variante in Variants akzeptiert |
| values | - | Liste der Varianten, die an den Visitor übergeben werden sollen |
[edit] Rückgabewert
R (möglicherweise cv-qualifiziert) void ist; andernfalls das Ergebnis der INVOKE<R>-Operation.[edit] Ausnahmen
Wirft std::bad_variant_access, wenn as-variant(value_i).valueless_by_exception() für irgendeine Variante value_i in values true ist.
[edit] Komplexität
Wenn die Anzahl der Varianten null oder eins ist, wird der Aufruf des aufrufbaren Objekts mit konstanter Zeit implementiert; d.h. er hängt nicht von der Anzahl der Typen ab, die in der Variante gespeichert werden können.
Wenn die Anzahl der Varianten größer als eins ist, hat der Aufruf des aufrufbaren Objekts keine Komplexitätsanforderungen.
[edit] Hinweise
Sei n (1 * ... * std::variant_size_v<std::remove_reference_t<VariantBases>>), Implementierungen generieren normalerweise eine Tabelle, die einem (möglicherweise mehrdimensionalen) Array von n Funktionszeigern für jede Spezialisierung von std::visit entspricht, was der Implementierung von virtuellen Funktionen ähnelt.
Implementierungen können auch eine switch-Anweisung mit n Zweigen für std::visit generieren (z.B. verwendet die MSVC STL-Implementierung eine switch-Anweisung, wenn n nicht größer als 256 ist).
Bei typischen Implementierungen kann die Zeitkomplexität des Aufrufs von v als gleich der des Zugriffs auf ein Element in einem (möglicherweise mehrdimensionalen) Array oder der Ausführung einer switch-Anweisung betrachtet werden.
| Feature-Test-Makro | Wert | Std | Feature |
|---|---|---|---|
__cpp_lib_variant |
202102L |
(C++23) (DR17) |
std::visit für von std::variant abgeleitete Klassen |
[edit] Beispiel
#include <iomanip> #include <iostream> #include <string> #include <type_traits> #include <variant> #include <vector> // the variant to visit using value_t = std::variant<int, long, double, std::string>; // 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<value_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 value_t w = std::visit([](auto&& arg) -> value_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(false, "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); } }
Ausgabe
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] Fehlerberichte
Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| LWG 2970 | C++17 | der Rückgabetyp von Überladung (1) hat die Wertkategorie des Ergebnisses der INVOKE-Operation nicht beibehalten |
wird beibehalten |
| LWG 3052 (P2162R2) |
C++17 | die Effekte waren undefiniert, wenn irgendein Typ in Variants kein std::variant ist |
spezifiziert |
[edit] Siehe auch
| (C++26) |
ruft den bereitgestellten Funktor mit dem vom variant gehaltenen Argument auf(public member function) |
tauscht mit einem anderen variant(public member function) |