std:: visit
|
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):
INVOKE
(
std::
forward
<
Visitor
>
(
v
)
,
std
::
get
<
indices
>
(
std::
forward
<
VariantBases
>
(
values
)
)
...
)
,
as-variant
(
values
)
.
index
(
)
...
ist.
INVOKE<R>
(
std::
forward
<
Visitor
>
(
v
)
,
std
::
get
<
indices
>
(
std::
forward
<
VariantBases
>
(
values
)
)
...
)
,
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.
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.
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
R
(möglicherweise cv-qualifiziert)
void
ist; andernfalls das Ergebnis der
INVOKE<R>
-Operation.
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) |