Inhaltsverzeichnis
Concepts
God is a concept by which we measure our pain.— John Lennon
Generische Lambdas mit auto
-Parametern seit C++14
auto show = [](auto x) { std::cout << x << '\n'; }
und generische Funktionen mit auto
-Parametern seit C++20
void show(auto x) { std::cout << x << '\n'; } // operator<< vorausgesetzt auto add(auto x, auto y) { return x + y; } // operator+ erforderlich
entsprechen Schablonen:
template <typename T> void show(T x) { std::cout << x << '\n'; }
Was geschieht, wenn einige Operationen für die Parametertypen nicht definiert sind? Vom Compiler erzeugte Fehlermeldungen sind nicht immer verständlich, besonders wenn Anforderungen erst tief in verschachtelten Schablonen benötigt werden.
Anforderungen
sind Prädikate, die beim Übersetzen ausgewertet werden. Sie beschränken Schablonen
template <typename T> requires std::is_integral_v<T> || std::is_floating_point_v<T> T add(T x, T y) { return x+y; }
Die Anforderungen können auch nach der Parameterliste angegeben werden. Mit einem concept
als benannte Anforderung
template <typename T> concept Number = std::is_integral_v<T> || std::is_floating_point_v<T>;
wird das Beispiel zu
template <typename T> requires Number<T> T add(T x, T y) { return x+y; }
Neben der Form mit der requires
-Klausel gibt es die "Kurzschrift" und die ganz "knappe Syntax".
Shorthand notation
nutzt concept
-Namen statt typename
:
template <Number T> T add(T x, T y) { return x+y; }
Terse syntax
war sehr umstritten. Daher verpassten Concepts den Einzug in C++17. Sie sind nun Bestandteil von C++20:
Number auto add(Number auto x, Number auto y) { return x+y; }
hat eine etwas andere Bedeutung als im Beispiel oben.
Unterschiedliche Parametertypen sind möglich.
Jeder Parametertyp ist unabhängig von dem anderen beschränkt.
Der Ergebnistyp kann wiederum ein anderer sein, sofern er die Anforderung von Number
erfüllt.
Jetzt ist es auch möglich, Anforderungen an auto
-Variablen zu stellen:
Number auto x = add(1, 2); Number auto y = add(1, 3.14); Number auto z = add(1, "3"); // Fehler in add(): char* Parameter ist nicht Number Number auto s = "Hello"; // Fehler: char* ist nicht Number
Concepts definieren
Anforderungen können logisch verknüpft werden (siehe concept Number
oben).
Innerhalb eines requires
-Ausdrucks sind
- einfache Anforderungen wie
x+y;
- Typanforderungen wie
typename T::value_type;
oder - zusammengesetzte Anforderungen möglich, die auch den Ergebnistyp einer Operation einschränken:
template<typename T> concept LessThanComparable = requires(T t) { { t<t } -> std::convertible_to<bool>; };
Die Standardbibliothek definiert grundlegende Anforderungen in <concepts>.