namespace cpp {}

C++ lernen, kennen, anwenden

Benutzer-Werkzeuge

Webseiten-Werkzeuge


kennen:include:variant
no way to compare when less than two revisions

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.


kennen:include:variant [2017-05-02 15:27] (aktuell) – angelegt - Externe Bearbeitung 127.0.0.1
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 von 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki