Künstliche Intelligenz
C++: Variadische Templates mithilfe von C++20-Konzepten beschränken
Heute möchte ich einen Aspekt der C++20-Konzepte beleuchten: Sie helfen dabei, den Datentyp eines variadischen Typ-Template-Parameters auf einen bestimmten Typ für alle Datentypen in der Menge einzuschränken.
Weiterlesen nach der Anzeige
Andreas Fertig ist erfahrener C++-Trainer und Berater, der weltweit Präsenz- sowie Remote-Kurse anbietet. Er engagiert sich im C++-Standardisierungskomitee und spricht regelmäßig auf internationalen Konferenzen. Mit C++ Insights ( hat er ein international anerkanntes Tool entwickelt, das C++-Programmierenden hilft, C++ noch besser zu verstehen.
Ich habe auf meinem englischen Blog bereits einige Artikel zu C++20-Konzepten veröffentlicht:
Angenommen, es gibt ein Funktions-Template Sum, das eine beliebige Anzahl von Parametern annehmen kann, deren Werte die Funktion addiert und das Ergebnis zurückgibt. Eine Implementierung mit einem C++17-Faltausdruck sieht folgendermaßen aus:
template
auto Sum(const T& val, const Ts&... vals)
{
return (val + ... + vals);
}
Die Implementierung funktioniert, lässt aber die Tür weit offen für die Verwendung von Sum mit gemischten Datentypen:
Sum(2, 3, 4, 5); // #A
Sum(2, 3, 4, 5.6); // #B
Ich bin mit #A zufrieden; aber ich möchte nicht, dass #B kompiliert wird. Wenn ich bei C++17 bleibe, kann ich Sum mithilfe eines static_assert und Type Traits einschränken:
Weiterlesen nach der Anzeige
template
auto Sum(const T& val, const Ts&... vals)
{
static_assert((std::is_same_v and ...));
return (val + ... + vals);
}
Ein Problem dieser Umsetzung liegt auf der Hand: Nutzer von Sum wissen nichts von der Einschränkung – es sei denn, sie schauen sich die Implementierungsdetails an. Das sollten sie nicht tun müssen. Dokumentation kann helfen, aber das Ziel ist es, so viel Dokumentation wie möglich im Code selbst zu belassen.
Es könnte ein weiteres Problem geben, wenn man eine andere Situation lösen würde. Was ist, wenn man Überladungen zulassen möchte? Mit static_assert ist dieser Weg komplett versperrt. Für den hier vorgestellten Fall mag das in Ordnung sein. Aber selbst hier: Was ist, wenn man eine Überladung für gemischte Gleitkommatypen zulassen will?
Konzepte zur Rettung
Wenn du Konzepte ins Spiel bringst, kann eine mögliche Lösung wie folgt aussehen:
template... Ts>
auto Sum(const T& val, const Ts&... vals)
{
return (val + ... + vals);
}
Ich verwende hier das Konzept std::same_as, um die Datentypen in Ts auf denselben Typ wie T zu beschränken. Das std::same_as funktioniert hier mit nur einem Parameter, da Konzepte die Fähigkeit haben, Lücken von links nach rechts zu füllen, und genau das macht der Compiler hier.
Variadische Parameter desselben Datentyps
Man kann sogar sagen, dass man ein variadisches Funktions-Template für einen einzigen bestimmten Datentyp wie int haben möchte.
Die Sum-Implementierung ändert sich wie folgt:
auto Sum(const std::same_as auto&... vals) { return (vals + ...); }
Konzepte sind ein großartiges, leistungsstarkes Werkzeug für deinen generischen Programmier-Werkzeugkasten.
(rme)