namespace cpp

C++ lernen, kennen, anwenden

Benutzer-Werkzeuge

Webseiten-Werkzeuge


kennen:include:variant

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

kennen:include:variant [2017-05-02 15:27] (aktuell)
Zeile 1: Zeile 1:
 +====== <​variant>​ ======
 +Die Kapsel ''​std::​variant<​Typen...>''​ bietet ab C++17 eine typsichere Alternative zu ''​union''​. Sie kann jeweils ein Objekt aus einer Liste von zur Übersetzungszeit bekannten Typen enthalten.
 +
 +<code cpp>
 +#include <​variant>​
 +#include <​iostream>​
 +
 +std::​variant<​char,​ double> findAnswer(int question)
 +{
 +  if (question == 42) return '​*';​
 +  return double(question);​
 +}
 +</​code>​
 +===== Einpacken =====
 +Wird bei der Initialisierung kein Wert zugewiesen, gilt der erste Typ.
 +Später kann jeder aufgelistete Typ zugewiesen werden:
 +<code cpp>
 +std::​variant<​char,​ double> v;
 +std::cout << "type index: " << v.index() << '​\n';​ // 0
 +
 +v = '​*';​
 +v = 42.0;
 +// v = 42;  // Fehler: Typ int unzulässig
 +v = findAnswer(6*9);​
 +</​code>​
 +
 +===== Auspacken =====
 +Der Zugriff auf das enthaltene Objekt erfolgt durch Angabe des Zieltyps oder die Indexnummer ''​v.index()''​ in der Typenliste, hier 0=''​char'',​ 1=''​double'':​
 +<code cpp>
 +if (auto* ptr = std::​get_if<​char>​(&​v)) std::cout << "char: " << *ptr << '​\n';​
 +if (auto* ptr = std::​get_if<​0>​(&​v)) ​   std::cout << "char: " << *ptr << '​\n';​
 +if (auto* ptr = std::​get_if<​1>​(&​v)) ​   std::cout << "​num: ​ " << *ptr << '​\n';​
 +</​code>​
 +Bei Erfolg liefert die Abfrage mit ''​std::​get_if<​Zieltyp>​()''​ einen gültigen Zeiger des Zieltyps.
 +Bei bekannten Typ kommt ''​std::​get<​Zieltyp>​()''​ zum Einsatz:
 +<code cpp>
 +if (std::​holds_alternative<​char>​(v)) ​
 +  std::cout << "char: " << std::​get<​char>​(v) << '​\n';​
 +else std::cout << "​num: ​ " << std::​get<​1>​(v) << '​\n';​
 +</​code>​
 +
 +Während die Angabe eines ungültigen Typs oder Typindexes einen Übersetzungsfehler erzeugt,
 +kann der Zugriff auf einen anderen als den aktuell enthaltenen Typ eine Ausnahme werfen:
 +<code cpp>
 +try
 +{
 +  // std::​get<​3>​(v);​ // Fehler: nur 0 und 1 zulässig
 +  std::​get<​char>​(v);​
 +}
 +catch(std::​bad_variant_access&​ err)
 +{
 +  std::cerr << err.what() << '​\n';​
 +}
 +</​code>​
 +
 +===== Besucher =====
 +Das enthaltene Objekt kann mit einem Besucher inspiziert werden, der Funktionsoperatoren für die möglicherweise enthaltenen Typen bereitstellt:​
 +<code cpp>
 +struct AnswerVisitor
 +{
 +  void operator()(char found) ​  { std::cout << "char: " << found << '​\n';​ }
 +  void operator()(double found) { std::cout << "​num: ​ " << found << '​\n';​ }
 +};
 +</​code>​
 +
 +<code cpp>
 +std::​visit(AnswerVisitor{},​ findAnswer(6*7));​
 +</​code>​
 +Auch ein generischer Lambdaausdruck ist zulässig:
 +<code cpp>
 +std::​visit([](auto&&​ something){ std::cout << "​found:​ " << something << '​\n';​ }, 
 +  findAnswer('​*'​)
 +);
 +</​code>​
 +
 +===== Leere Varianten =====
 +Besitzt ein (erster) Typ der Typliste keinen Standardkonstruktor,​ kann ''​std::​monostate''​ als erster Typ angegeben werden, um einer Variante keinen Anfangswert zuweisen zu müssen:
 +<code cpp>
 +struct S
 +{
 +    S(int i) : i(i) {}
 +    int i;
 +};
 +
 +std::​variant<​std::​monostate,​ S> v;
 +v = 42;
 +</​code>​
 +
 +===== Objekt aus Parametern bauen =====
 +Objekte lassen sich aus deren Konstruktorparametern vor Ort erzeugen:
 +<code cpp>
 +std::​variant<​int,​ std::​string>​ v1(std::​in_place_type<​std::​string>,​ 10, '​-'​);​ // Typangabe erforderlich
 +std::​variant<​int,​ std::​string>​ v2(std::​in_place_index<​1>,​ 10, '​-'​); ​         // Index in Typliste
 +std::​variant<​int,​ std::​string>​ v3;
 +v.emplace<​std::​string>​(10,​ '​-'​); ​                                            // nachträglich einsetzen
 +
 +std::cout << std::​get<​1>​(v1) << '​\n';​ // v2, v3 ...
 +</​code>​
  
kennen/include/variant.txt · Zuletzt geändert: 2017-05-02 15:27 (Externe Bearbeitung)