Namensräume
Varianten
Aktionen

std::visit

Von cppreference.com
< cpp‎ | utility‎ | variant
 
 
Dienstprogramm-Bibliotheken
Sprachunterstützung
Typunterstützung (Basistypen, RTTI)
Bibliotheks-Feature-Test-Makros (C++20)
Programm-Dienstprogramme
Variadische Funktionen
Coroutine-Unterstützung (C++20)
Vertragsunterstützung (C++26)
Drei-Wege-Vergleich
(C++20)
(C++20)(C++20)(C++20)  
(C++20)(C++20)(C++20)

Allgemeine Hilfsmittel
Relationale Operatoren (in C++20 veraltet)
 
 
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)

1) Ruft v auf, als ob durch

INVOKE(std::forward<Visitor>(v),
       std::get<indices>(std::forward<VariantBases>(values))...)
,

wobei indices as-variant(values).index()... ist.
2) Ruft v auf, als ob durch

INVOKE<R>(std::forward<Visitor>(v),
          std::get<indices>(std::forward<VariantBases>(values))...)
,

wobei indices as-variant(values).index()... ist.

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.

3-6) Die Exposition-Only-Funktionstemplates 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.
3,4) Gibt value zurück.
5,6) Gibt std::move(value) 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

1) Das Ergebnis der INVOKE-Operation. Der Rückgabetyp ist der Typ, der durch Anwendung von decltype auf das Ergebnis erhalten wird.
2) Nichts, wenn R (möglicherweise cv-qualifiziert) void ist; andernfalls das Ergebnis der INVOKE<R>-Operation.
3-6) Ein std::variant-Wert, der aus value konvertiert wurde.

[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) [bearbeiten]
tauscht mit einem anderen variant
(public member function) [bearbeiten]