std::visit
| Definiert in Header <variant>
|
||
template< class Visitor, class... Variants >
constexpr /* see below */ 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) |
| Helfer-Templates |
||
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 aufrufbares Objekt, das mit jeder Kombination von Typen aus Varianten aufgerufen werden kann) auf die Varianten values an.
Gegeben VariantBases als decltype(as-variant(std::forward<Variants>(values))... (ein Pack von sizeof...(Variants) Typen):
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.
v auf, als ob durch
INVOKE<R>(std::forward<Visitor>(v),std::get<indices>(std::forward<VariantBases>(values))...),
wobei indices gleich as-variant(values).index()... ist.
Diese Überladungen nehmen nur dann an der Überladungsauflösung teil, wenn jeder Typ in VariantBases ein gültiger Typ ist. Falls 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) unterschiedliche Typen oder Wertkategorien für verschiedene indices haben, ist das Programm fehlerhaft.
as-variant Funktionstemplates akzeptieren einen Wert, dessen Typ 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.value zurück.std::move(value) zurück.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) |