Namespaces
Variants

std:: visit

From cppreference.net
Utilities library
Definiert im Header <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)
Hilfsvorlagen
template < class ... Ts >
auto && as - variant ( std:: variant < Ts... > & value ) ;
(3) ( nur zur Darstellung* )
template < class ... Ts >
auto && as - variant ( const std:: variant < Ts... > & value ) ;
(4) ( nur zur Darstellung* )
template < class ... Ts >
auto && as - variant ( std:: variant < Ts... > && value ) ;
(5) ( nur zur Darstellung* )
template < class ... Ts >
auto && as - variant ( const std:: variant < Ts... > && value ) ;
(6) ( nur zur Darstellung* )

Wendet den Besucher v (ein Callable , der mit beliebiger Kombination von Typen aus Variants aufgerufen werden kann) auf die Variants values an.

Gegeben VariantBases als 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 gleich 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 ist as-variant ( values ) . index ( ) ... .

Diese Überladungen nehmen nur dann 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 haben, ist das Programm fehlerhaft.

3-6) Die ausschließlich zur Darstellung bestimmten as-variant Funktions-Templates akzeptieren einen Wert, dessen Typ für deduziert werden kann für std:: variant < Ts... > (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.

Inhaltsverzeichnis

Parameter

v - ein Callable , das jede mögliche Alternative aus jeder Variante in Variants akzeptiert
values - Liste der Varianten, die an den Besucher übergeben werden sollen

Rückgabewert

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

Exceptions

Wirft std::bad_variant_access falls as-variant ( value_i ) . valueless_by_exception ( ) für irgendein Variant value_i in values true ist.

Komplexität

Wenn die Anzahl der Varianten null oder eins beträgt, erfolgt der Aufruf des aufrufbaren Objekts in konstanter Zeit; 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.

Hinweise

Sei n gleich ( 1 * ... * std:: variant_size_v < std:: remove_reference_t < VariantBases >> ) , Implementierungen erzeugen typischerweise 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 Verzweigungen für std::visit generieren (z.B. verwendet die MSVC STL-Implementierung eine switch-Anweisung, wenn n nicht größer als 256 ist).

Auf typischen Implementierungen kann die Zeitkomplexität des Aufrufs von v als gleichwertig mit dem Zugriff 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 Klassen abgeleitet von std::variant

Beispiel

#include <iomanip>
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>
// die zu besuchende Variante
using value_t = std::variant<int, long, double, std::string>;
// Hilfstyp für den Besucher #4
template<class... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
// explizite Deduktion-Anleitung (ab C++20 nicht mehr benötigt)
template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
int main()
{
    std::vector<value_t> vec = {10, 15l, 1.5, "hallo"};
    for (auto& v: vec)
    {
        // 1. void visitor, nur für Nebeneffekte aufgerufen (hier für E/A)
        std::visit([](auto&& arg){ std::cout << arg; }, v);
        // 2. wertrückgebender Besucher, demonstriert die Idiomatik der Rückgabe einer weiteren Variante
        value_t w = std::visit([](auto&& arg) -> value_t { return arg + arg; }, v);
        // 3. typübereinstimmender Visitor: ein Lambda, das jeden Typ unterschiedlich behandelt
        std::cout << ". Nach der Verdopplung enthält die Variante ";
        std::visit([](auto&& arg)
        {
            using T = std::decay_t<decltype(arg)>;
            if constexpr (std::is_same_v<T, int>)
                std::cout << "int mit Wert " << arg << '\n';
            else if constexpr (std::is_same_v<T, long>)
                std::cout << "long mit Wert " << arg << '\n';
            else if constexpr (std::is_same_v<T, double>)
                std::cout << "double mit Wert " << arg << '\n';
            else if constexpr (std::is_same_v<T, std::string>)
                std::cout << "std::string mit Wert " << std::quoted(arg) << '\n';
            else
                static_assert(false, "nicht erschöpfender Visitor!");
        }, w);
    }
    for (auto& v: vec)
    {
        // 4. another type-matching visitor: eine Klasse mit 3 überladenen operator()'s
        // Hinweis: Der `(auto arg)` Template-Operator() bindet an `int` und `long`
        //       in diesem Fall, aber in dessen Abwesenheit der `(double arg)` operator()
        //       *wird auch* an `int` und `long` binden, da beide implizit
        //       in double konvertierbar. Bei Verwendung dieser Form ist Vorsicht geboten
        //       dass implizite Konvertierungen korrekt behandelt werden.
        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"

Fehlerberichte

Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR Angewendet auf Verhalten wie veröffentlicht Korrektes Verhalten
LWG 2970 C++17 der Rückgabetyp der Überladung (1) bewahrte nicht die
Wertkategorie des Ergebnisses der INVOKE -Operation
bewahrt
LWG 3052
( P2162R2 )
C++17 die Effekte waren nicht spezifiziert, falls irgendein Typ
in Variants kein std::variant ist
spezifiziert

Siehe auch

(C++26)
ruft den bereitgestellten Funktor mit dem im variant gehaltenen Argument auf
(öffentliche Elementfunktion)
tauscht mit einem anderen variant
(öffentliche Elementfunktion)