<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Metaprogramming on kenji.blog</title><link>http://kenji.blog/de/tags/metaprogramming/</link><description>Recent content in Metaprogramming on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>de</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 14:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/de/tags/metaprogramming/index.xml" rel="self" type="application/rss+xml"/><item><title>Berechnungen zur Kompilierzeit mit C++ Template-Metaprogrammierung</title><link>http://kenji.blog/de/p/cpp-template-metaprogramming-compile-time-computation/</link><pubDate>Sat, 12 Sep 2026 14:00:00 +0900</pubDate><guid>http://kenji.blog/de/p/cpp-template-metaprogramming-compile-time-computation/</guid><description>&lt;img src="http://kenji.blog/p/cpp-template-metaprogramming-compile-time-computation/img/eyecatch.jpg" alt="Featured image of post Berechnungen zur Kompilierzeit mit C++ Template-Metaprogrammierung" />&lt;p>Die „Template-Metaprogrammierung“ (Template Metaprogramming: TMP) ist wahrscheinlich die größte Attraktion der Sprache C++, aber gleichzeitig auch ihr größtes Mysterium. Dies ist eine Technik, bei der Berechnungen, die normalerweise zur Laufzeit (Run-time) des Programms durchgeführt werden, auf die Kompilierzeit (Compile-time) vorgezogen werden, wenn der Compiler den Quellcode interpretiert und die Binärdatei generiert.&lt;/p>
&lt;p>In diesem Artikel werden wir im Detail erklären, wie die C++-Templates historisch gesehen überhaupt zu ihrer Rechenkapazität gekommen sind, und die Entwicklung von klassischem SFINAE über das moderne &lt;code>constexpr&lt;/code> und &lt;code>if constexpr&lt;/code> bis hin zu &lt;code>consteval&lt;/code> und Concepts (Konzepten) in C++20 anhand von praktischen Codebeispielen und mathematischem Hintergrund beleuchten.&lt;/p>
&lt;hr>
&lt;h2 id="1-die-anfänge-der-template-metaprogrammierung-die-zufällige-entdeckung-der-turing-vollständigkeit">1. Die Anfänge der Template-Metaprogrammierung: Die zufällige Entdeckung der Turing-Vollständigkeit
&lt;/h2>&lt;h3 id="11-was-ist-turing-vollständigkeit">1.1 Was ist Turing-Vollständigkeit?
&lt;/h3>&lt;p>In der Informatik bedeutet „turing-vollständig“ (Turing Complete) zu sein, dass man über dieselbe Rechenleistung wie eine universelle Turingmaschine verfügt. Einfach ausgedrückt handelt es sich um ein System, das „bedingte Verzweigungen“ und „Endlosschleifen (oder Rekursionen)“ ausdrücken und jeden beliebigen Algorithmus beschreiben und ausführen kann.&lt;/p>
&lt;h3 id="12-die-entdeckung-von-erwin-unruh">1.2 Die Entdeckung von Erwin Unruh
&lt;/h3>&lt;p>Im Jahr 1994 präsentierte Erwin Unruh auf einem Treffen des C++-Standardisierungskomitees einen C++-Code. Dieser Code schlug zwar bei der Kompilierung fehl, aber interessanterweise &lt;strong>enthielt die vom Compiler ausgegebene Fehlermeldung eine Folge von Primzahlen&lt;/strong>.&lt;/p>
&lt;p>Der Compiler führte während des Prozesses der Template-Instanziierung rekursive Verarbeitungen durch und gab das Berechnungsergebnis als Fehlermeldung aus. Dies war der Moment, in dem bewiesen wurde, dass die Template-Funktion von C++ ein &lt;strong>turing-vollständiges Berechnungssystem&lt;/strong> enthielt, das selbst der Sprachdesigner Bjarne Stroustrup nicht beabsichtigt hatte.&lt;/p>
&lt;hr>
&lt;h2 id="2-klassische-template-metaprogrammierung-c98--c03">2. Klassische Template-Metaprogrammierung (C++98 / C++03)
&lt;/h2>&lt;p>Frühe Template-Metaprogrammierung nutzte Strukturen (&lt;code>struct&lt;/code>) und Template-Spezialisierung (Template Specialization) in einem Stil, der der reinen funktionalen Programmierung ähnelte.&lt;/p>
&lt;h3 id="21-berechnung-der-fakultät-factorial">2.1 Berechnung der Fakultät (Factorial)
&lt;/h3>&lt;p>Schauen wir uns zunächst das grundlegendste Beispiel an: die Berechnung der Fakultät ($N!$). Mathematisch ist sie wie folgt definiert:&lt;/p>
$$
N! =
\begin{cases}
1 &amp; (N = 0) \\
N \times (N - 1)! &amp; (N > 0)
\end{cases}
$$&lt;p>Wenn man dies in C++98-Templates schreibt, sieht das folgendermaßen aus:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Primäres Template (Allgemeiner Fall der Rekursion)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">template&lt;/span> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">struct&lt;/span> &lt;span class="nc">Factorial&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">static&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">N&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">Factorial&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">N&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="o">&amp;gt;::&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Explizite Spezialisierung des Templates (Basisfall der Rekursion)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">template&lt;/span> &lt;span class="o">&amp;lt;&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">struct&lt;/span> &lt;span class="nc">Factorial&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">static&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Wird zur Kompilierzeit berechnet und als Konstante eingebettet
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;5! = &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">Factorial&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="o">&amp;gt;::&lt;/span>&lt;span class="n">value&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Das Wichtige hierbei ist, dass &lt;code>Factorial&amp;lt;5&amp;gt;::value&lt;/code> nicht zur Laufzeit berechnet, sondern zur Kompilierzeit aufgelöst wird, und in der endgültigen Binärdatei wird ein Code generiert, der äquivalent zu &lt;code>std::cout &amp;lt;&amp;lt; &amp;quot;5! = &amp;quot; &amp;lt;&amp;lt; 120 &amp;lt;&amp;lt; std::endl;&lt;/code> ist. Dadurch wird der Laufzeit-Overhead auf null reduziert.&lt;/p>
&lt;h3 id="22-fibonacci-folge-und-komplexität">2.2 Fibonacci-Folge und Komplexität
&lt;/h3>&lt;p>Als Nächstes berechnen wir die Fibonacci-Folge. Die Rekursionsgleichung lautet wie folgt:&lt;/p>
$$
F_n = F_{n-1} + F_{n-2} \quad (F_0 = 0, F_1 = 1)
$$&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">template&lt;/span> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">struct&lt;/span> &lt;span class="nc">Fib&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">static&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Fib&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">N&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="o">&amp;gt;::&lt;/span>&lt;span class="n">value&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">Fib&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">N&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="o">&amp;gt;::&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">template&lt;/span> &lt;span class="o">&amp;lt;&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">struct&lt;/span> &lt;span class="nc">Fib&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="k">static&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">template&lt;/span> &lt;span class="o">&amp;lt;&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">struct&lt;/span> &lt;span class="nc">Fib&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="k">static&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Wenn diese Implementierung mit einer rekursiven Funktion zur Laufzeit geschrieben wird, wird dieselbe Berechnung viele Male wiederholt, was zu einer exponentiellen Zeitkomplexität von $O(2^N)$ führt. Bei der Instanziierung von Templates zur Kompilierzeit gibt es jedoch die Eigenschaft, dass &lt;strong>Typen mit denselben Template-Argumenten nur einmal instanziiert werden&lt;/strong> (ein Effekt ähnlich der Memoisation). Daher beträgt die Berechnungskomplexität zur Kompilierzeit effektiv $O(N)$.&lt;/p>
&lt;p>Das folgende Diagramm zeigt, wie der Compiler die Instanzen auflöst.&lt;/p>
&lt;pre class="mermaid">
graph TD
A[&amp;#34;Fib&amp;lt;4&amp;gt;&amp;#34;] --&amp;gt; B[&amp;#34;Fib&amp;lt;3&amp;gt;&amp;#34;]
A[&amp;#34;Fib&amp;lt;4&amp;gt;&amp;#34;] --&amp;gt; C[&amp;#34;Fib&amp;lt;2&amp;gt;&amp;#34;]
B[&amp;#34;Fib&amp;lt;3&amp;gt;&amp;#34;] --&amp;gt; D[&amp;#34;Fib&amp;lt;2&amp;gt;&amp;#34;]
B[&amp;#34;Fib&amp;lt;3&amp;gt;&amp;#34;] --&amp;gt; E[&amp;#34;Fib&amp;lt;1&amp;gt;&amp;#34;]
C[&amp;#34;Fib&amp;lt;2&amp;gt;&amp;#34;] --&amp;gt; F[&amp;#34;Fib&amp;lt;1&amp;gt;&amp;#34;]
C[&amp;#34;Fib&amp;lt;2&amp;gt;&amp;#34;] --&amp;gt; G[&amp;#34;Fib&amp;lt;0&amp;gt;&amp;#34;]
style D fill:#f9f,stroke:#333,stroke-width:2px
style C fill:#f9f,stroke:#333,stroke-width:2px
&lt;/pre>
&lt;p>Oben wird &lt;code>Fib&amp;lt;2&amp;gt;&lt;/code>, das dieselbe Farbe und Form hat, nur einmal im Compiler instanziiert, und ab dem zweiten Mal wird die zwischengespeicherte Typdefinition verwendet.&lt;/p>
&lt;hr>
&lt;h2 id="3-sfinae-und-type-traits-c11">3. SFINAE und Type Traits (C++11)
&lt;/h2>&lt;p>Mit der Weiterentwicklung der Metaprogrammierung wurde nicht nur die „Berechnung von Werten“, sondern auch die „Manipulation und Bewertung von Typen“ immer wichtiger. Hier kommt &lt;strong>SFINAE&lt;/strong> (Substitution Failure Is Not An Error: Ein Ersetzungsfehler ist kein Fehler) ins Spiel.&lt;/p>
&lt;h3 id="31-der-sfinae-mechanismus">3.1 Der SFINAE-Mechanismus
&lt;/h3>&lt;p>Bei der Überladungsauflösung von Template-Funktionen leitet der Compiler die Template-Argumente aus den übergebenen Argumenten ab und ersetzt die Typen in der Signatur (dem Deklarationsteil der Funktion). Wenn es dabei zu einem Typwiderspruch kommt und die Ersetzung fehlschlägt, gibt der Compiler nicht sofort einen Kompilierungsfehler aus, sondern &lt;strong>schließt diesen Überladungskandidaten stillschweigend aus&lt;/strong> und sucht nach dem nächsten Kandidaten.&lt;/p>
&lt;pre class="mermaid">
stateDiagram-v2
[*] --&amp;gt; A
A[&amp;#34;Aufruf der Template-Funktion&amp;#34;] --&amp;gt; B[&amp;#34;Typableitung&amp;#34;]
B[&amp;#34;Typableitung&amp;#34;] --&amp;gt; C[&amp;#34;Ersetzung der Signatur&amp;#34;]
C[&amp;#34;Ersetzung der Signatur&amp;#34;] --&amp;gt; D[&amp;#34;Ersetzung erfolgreich?&amp;#34;]
D[&amp;#34;Ersetzung erfolgreich?&amp;#34;] --&amp;gt; E[&amp;#34;Zum Kandidaten hinzufügen&amp;#34;] : Yes
D[&amp;#34;Ersetzung erfolgreich?&amp;#34;] --&amp;gt; F[&amp;#34;Als Kandidat ausschließen (nicht als Fehler) (SFINAE)&amp;#34;] : No
E[&amp;#34;Zum Kandidaten hinzufügen&amp;#34;] --&amp;gt; G[&amp;#34;Überladungsauflösung&amp;#34;]
F[&amp;#34;Als Kandidat ausschließen (nicht als Fehler) (SFINAE)&amp;#34;] --&amp;gt; G[&amp;#34;Überladungsauflösung&amp;#34;]
G[&amp;#34;Überladungsauflösung&amp;#34;] --&amp;gt; [*]
&lt;/pre>
&lt;h3 id="32-bedingte-kompilierung-mit-stdenable_if">3.2 Bedingte Kompilierung mit std::enable_if
&lt;/h3>&lt;p>Durch die Verwendung des in C++11 eingeführten Headers &lt;code>&amp;lt;type_traits&amp;gt;&lt;/code> und &lt;code>std::enable_if&lt;/code> können Funktionen nur für Typen aktiviert werden, die bestimmte Bedingungen erfüllen.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;type_traits&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Überladung, die nur aktiviert wird, wenn T ein Ganzzahltyp ist
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">template&lt;/span> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="k">typename&lt;/span> &lt;span class="n">T&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">typename&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">enable_if&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">is_integral&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">T&lt;/span>&lt;span class="o">&amp;gt;::&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="o">&amp;gt;::&lt;/span>&lt;span class="n">type&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">print_type&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">T&lt;/span> &lt;span class="n">val&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Integer: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">val&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Überladung, die nur aktiviert wird, wenn T ein Gleitkommatyp ist
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">template&lt;/span> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="k">typename&lt;/span> &lt;span class="n">T&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">typename&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">enable_if&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">is_floating_point&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">T&lt;/span>&lt;span class="o">&amp;gt;::&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="o">&amp;gt;::&lt;/span>&lt;span class="n">type&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">print_type&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">T&lt;/span> &lt;span class="n">val&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Floating point: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">val&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">print_type&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">42&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Integer: 42
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">print_type&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mf">3.1415&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Floating point: 3.1415
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// print_type(&amp;#34;str&amp;#34;); // Kompilierungsfehler: Keine passende Funktion
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Dieser Ansatz war sehr mächtig, aber Schreibweisen wie &lt;code>typename std::enable_if&amp;lt;...&amp;gt;::type&lt;/code> waren extrem wortreich und trugen dazu bei, dass die C++-Metaprogrammierung als „kryptisch“ gemieden wurde.&lt;/p>
&lt;hr>
&lt;h2 id="4-paradigmenwechsel-die-einführung-von-constexpr-c11c14">4. Paradigmenwechsel: Die Einführung von constexpr (C++11/C++14)
&lt;/h2>&lt;p>In C++11 wurde das Schlüsselwort &lt;code>constexpr&lt;/code> eingeführt, was eine Revolution in der Geschichte der Metaprogrammierung darstellte. Dadurch wurde es möglich, &lt;strong>Kompilierzeitberechnungen mit der üblichen Funktionsschreibweise durchzuführen&lt;/strong>, ohne auf unnatürliche Template-Rekursionen zurückgreifen zu müssen.&lt;/p>
&lt;h3 id="41-constexpr-in-c11">4.1 constexpr in C++11
&lt;/h3>&lt;p>Für &lt;code>constexpr&lt;/code>-Funktionen zum Zeitpunkt von C++11 gab es die strenge Einschränkung, dass der „Rumpf nur aus einer einzigen &lt;code>return&lt;/code>-Anweisung bestehen durfte“. Daher mussten Schleifen vermieden und auf ternäre Operatoren und Rekursion zurückgegriffen werden.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// C++11 constexpr Fibonacci
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">constexpr&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="nf">fib_cxx11&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="nl">n&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">fib_cxx11&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">fib_cxx11&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="42-lockerung-von-constexpr-in-c14">4.2 Lockerung von constexpr in C++14
&lt;/h3>&lt;p>In C++14 wurde diese Einschränkung stark gelockert, sodass die Deklaration von lokalen Variablen, &lt;code>if&lt;/code>-Anweisungen, &lt;code>for&lt;/code>-Schleifen usw. innerhalb von &lt;code>constexpr&lt;/code>-Funktionen verwendet werden konnten. Dadurch ist es möglich, Algorithmen genauso unkompliziert wie für die Laufzeit zu schreiben.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// C++14 constexpr Fibonacci
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">constexpr&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="nf">fib_cxx14&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">temp&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">temp&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Dieser Code wird zur Kompilierzeit berechnet, wenn er zur Kompilierzeit ausgewertet werden kann, und als normale Funktion zur Laufzeit ausgeführt, wenn die Argumente zur Laufzeit übergeben werden.&lt;/p>
&lt;pre class="mermaid">
graph TD
subgraph &amp;#34;Kompilierzeit (Compile Time)&amp;#34;
A[&amp;#34;Quellcode-Analyse&amp;#34;] --&amp;gt; B[&amp;#34;AST-Konstruktion&amp;#34;]
B[&amp;#34;AST-Konstruktion&amp;#34;] --&amp;gt; C[&amp;#34;Auswertung von constexpr-Funktionen&amp;#34;]
C[&amp;#34;Auswertung von constexpr-Funktionen&amp;#34;] --&amp;gt; D[&amp;#34;Einbettung von Konstanten (z. B. 120)&amp;#34;]
end
subgraph &amp;#34;Laufzeit (Runtime)&amp;#34;
E[&amp;#34;Programmstart&amp;#34;] --&amp;gt; F[&amp;#34;Direkte Nutzung der berechneten Ergebnisse&amp;#34;]
F[&amp;#34;Direkte Nutzung der berechneten Ergebnisse&amp;#34;] --&amp;gt; G[&amp;#34;Ausführung mit null Rechenkosten&amp;#34;]
end
D[&amp;#34;Einbettung von Konstanten (z. B. 120)&amp;#34;] --&amp;gt; E[&amp;#34;Programmstart&amp;#34;]
&lt;/pre>
&lt;hr>
&lt;h2 id="5-beherrschung-der-statischen-bedingten-verzweigung-if-constexpr-c17">5. Beherrschung der statischen bedingten Verzweigung: if constexpr (C++17)
&lt;/h2>&lt;p>In C++17 wurde &lt;code>if constexpr&lt;/code> eingeführt, womit die wortreiche Überladungsauflösung mittels SFINAE der Vergangenheit angehört. Es handelt sich um eine &lt;code>if&lt;/code>-Anweisung, die zur Kompilierzeit ausgewertet wird. Ein Block, dessen Bedingung &lt;code>false&lt;/code> ist, wird gar nicht erst instanziiert und komplett aus dem Kompilierungsziel verworfen.&lt;/p>
&lt;p>Wenn wir das vorherige SFINAE-Beispiel mit &lt;code>if constexpr&lt;/code> umschreiben, wird es überraschend einfach.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;type_traits&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">template&lt;/span> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="k">typename&lt;/span> &lt;span class="n">T&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">void&lt;/span> &lt;span class="n">print_type&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">T&lt;/span> &lt;span class="n">val&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="nf">constexpr&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">is_integral_v&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">T&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Integer: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">val&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="nf">constexpr&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">is_floating_point_v&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">T&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Floating point: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">val&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Other type&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Durch die Verwendung von &lt;code>if constexpr&lt;/code> können Verarbeitungen für verschiedene Typen in derselben Funktionstemplate zusammengefasst werden, was die Lesbarkeit des Codes dramatisch verbessert.&lt;/p>
&lt;hr>
&lt;h2 id="6-die-wahre-stärke-von-modernem-c-consteval-und-concepts-c20">6. Die wahre Stärke von modernem C++: consteval und Concepts (C++20)
&lt;/h2>&lt;p>C++20 war das größte Update seit C++11. Auch im Bereich der Metaprogrammierung hat es eine dramatische Entwicklung durchgemacht.&lt;/p>
&lt;h3 id="61-berechnungen-zwingend-zur-kompilierzeit-consteval">6.1 Berechnungen zwingend zur Kompilierzeit: consteval
&lt;/h3>&lt;p>Während &lt;code>constexpr&lt;/code> eine Anweisung war, die besagte „wenn die Bedingungen erfüllt sind, berechne zur Kompilierzeit“, aber auch die Auswertung zur Laufzeit erlaubte, definiert das in C++20 hinzugefügte &lt;code>consteval&lt;/code> &lt;strong>eine sofortige Funktion (Immediate Function), die „zwingend zur Kompilierzeit ausgewertet werden muss“&lt;/strong>. Wenn versucht wird, sie zur Laufzeit auszuwerten, führt dies zu einem Kompilierungsfehler.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Erzwingt definitiv die Berechnung zur Kompilierzeit
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">consteval&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="nf">square&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">constexpr&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">square&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// OK: Auswertung zur Kompilierzeit
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// int b = square(x); // Fehler: x ist eine Laufzeitvariable und kann nicht ausgewertet werden
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="62-klärung-von-template-anforderungen-concepts">6.2 Klärung von Template-Anforderungen: Concepts
&lt;/h3>&lt;p>Eine der größten Schwächen der Metaprogrammierung waren die „kryptischen Fehlermeldungen“. Wenn ein falscher Typ an ein Template-Argument übergeben wurde, wurden manchmal hunderte von Zeilen unverständlicher Fehlermeldungen ausgegeben.&lt;/p>
&lt;p>Mit den &lt;strong>Concepts (Konzepten)&lt;/strong> von C++20 können die Typbeschränkungen, die ein Template akzeptiert, in einer Form spezifiziert werden, die natürlicher Sprache nahekommt, und auch die Fehlermeldungen werden extrem klar.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;concepts&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Erfordert, dass T ein Ganzzahltyp ist
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">template&lt;/span> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">integral&lt;/span> &lt;span class="n">T&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">T&lt;/span> &lt;span class="n">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">T&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">T&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">20&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// OK
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// std::cout &amp;lt;&amp;lt; add(1.5, 2.5) &amp;lt;&amp;lt; std::endl; // Fehler: std::integral nicht erfüllt
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="7-praxisbeispiel-primzahltest-zur-kompilierzeit-und-algorithmenoptimierung">7. Praxisbeispiel: Primzahltest zur Kompilierzeit und Algorithmenoptimierung
&lt;/h2>&lt;p>Lassen Sie uns nun unser gesamtes Wissen nutzen, um einen Code für einen Primzahltest zur Kompilierzeit zu schreiben. Hier verwenden wir eine moderne C++20-Funktion (&lt;code>consteval&lt;/code>).&lt;/p>
&lt;p>Die Zeitkomplexität eines Primzahltest-Algorithmus ist bei naiver Prüfung $O(N)$, aber da es ausreicht, bis $\sqrt{N}$ zu prüfen, beträgt sie beim optimalen Algorithmus $O(\sqrt{N})$.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Hilfsfunktion zur Berechnung des ganzzahligen Teils der Quadratwurzel zur Kompilierzeit
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">consteval&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="nf">compile_time_sqrt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">res&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">res&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">res&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">res&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Primzahltest mit C++20 consteval
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">consteval&lt;/span> &lt;span class="kt">bool&lt;/span> &lt;span class="nf">is_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">limit&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">compile_time_sqrt&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="n">limit&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Wird vollständig zur Kompilierzeit ausgewertet
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">static_assert&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">is_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">104729&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;104729 should be prime!&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">static_assert&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">is_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">100&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;100 should not be prime!&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">constexpr&lt;/span> &lt;span class="kt">bool&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">is_prime&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">9973&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Is 9973 prime? &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">boolalpha&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Im obigen Code sind sowohl &lt;code>compile_time_sqrt&lt;/code> als auch &lt;code>is_prime&lt;/code> als &lt;code>consteval&lt;/code> spezifiziert, sodass diese Berechnungen zu 100 % zur Kompilierzeit abgeschlossen sind. In der Binärdatei der ausführbaren Datei sind lediglich Konstanten (boolesche Werte) wie &lt;code>true&lt;/code> oder &lt;code>false&lt;/code> eingebettet.&lt;/p>
&lt;h3 id="71-mathematischer-ausdruck-der-komplexität">7.1 Mathematischer Ausdruck der Komplexität
&lt;/h3>&lt;p>Beim Primzahltest ist der maximale zu prüfende Wert $\lfloor \sqrt{N} \rfloor$.
Daher ist die Worst-Case-Zeitkomplexität $T(N)$ wie folgt:&lt;/p>
$$
T(N) = O(\sqrt{N})
$$&lt;p>Wenn dies zur Laufzeit berechnet wird, kann es beispielsweise bei kryptografischen Prozessen oder der Initialisierung groß angelegter Simulationen zu Verzögerungen von Hunderten von Millisekunden bis zu einigen Sekunden kommen. Wenn jedoch die Template-Metaprogrammierung zur Kompilierzeit verwendet wird, werden die Kosten von $T(N)$ vollständig auf der Seite des Compilers getragen, und die Kosten zur Ausführungszeit für den Benutzer betragen $O(1)$.&lt;/p>
&lt;hr>
&lt;h2 id="8-licht-und-schatten-der-kompilierzeitberechnung">8. Licht und Schatten der Kompilierzeitberechnung
&lt;/h2>&lt;p>Bisher haben wir die mächtigen Berechnungsfunktionen von C++ zur Kompilierzeit gesehen, aber sie sollten nicht bedingungslos überbeansprucht werden.&lt;/p>
&lt;h3 id="vorteile">Vorteile
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Null Overhead zur Laufzeit&lt;/strong>: Da die Berechnungsergebnisse als Konstanten eingebettet werden, ist die Ausführungsgeschwindigkeit maximal.&lt;/li>
&lt;li>&lt;strong>Frühzeitige Fehlererkennung&lt;/strong>: In Kombination mit &lt;code>static_assert&lt;/code> etc. können Logikfehler oder Typinkonsistenzen bereits zum Zeitpunkt der Kompilierung sicher abgefangen werden.&lt;/li>
&lt;/ul>
&lt;h3 id="nachteile">Nachteile
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Explosion der Build-Zeiten&lt;/strong>: Da Berechnungen innerhalb des Compilers in einer speziellen Interpreter-Umgebung (dem AST-Evaluator des Compilers) durchgeführt werden, sind sie viel langsamer als die Ausführung von nativem Code zur Laufzeit. Wenn riesige Matrixberechnungen usw. zur Kompilierzeit durchgeführt werden, besteht die Gefahr, dass die Build-Zeit auf mehrere Stunden ansteigt.&lt;/li>
&lt;li>&lt;strong>Aufblähen der Binärdatei (Code Bloat)&lt;/strong>: Wenn Templates mit vielen verschiedenen Typen instanziiert werden, werden viele Funktionen generiert, was zu dem Phänomen führen kann, dass die Größe der ausführbaren Datei stark anwächst.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="9-fazit">9. Fazit
&lt;/h2>&lt;p>Die Template-Metaprogrammierung in C++ begann als „Zufallsprodukt (Hack)“, bei dem aus Fehlermeldungen Primzahlen ausgegeben wurden, und hat sich durch jahrelange Standardisierungsarbeit zu raffinierten Sprachfunktionen (&lt;code>constexpr&lt;/code>, &lt;code>if constexpr&lt;/code>, &lt;code>Concepts&lt;/code>) weiterentwickelt.&lt;/p>
&lt;p>Im modernen C++ ist die Hürde für den Begriff „Metaprogrammierung“ drastisch gesunken, und es ist möglich, von den Vorteilen der Kompilierzeitberechnung zu profitieren, während man Code genauso intuitiv wie in normalen Programmen schreibt.&lt;/p>
&lt;p>In Bereichen, in denen ultimative Leistung gefordert ist, wie bei eingebetteten Systemen, Spiele-Engines und Hochfrequenzhandelssystemen (HFT), wird diese Technologie weiterhin eine unverzichtbare Waffe sein.&lt;/p>
&lt;p>Die Entwicklung von C++ ist noch nicht abgeschlossen. Zukünftige Standards wie C++23 und C++26 werden noch leistungsfähigere Funktionen wie die Reflexion zur Kompilierzeit (Compile-time Reflection) mit sich bringen. Wir hoffen, dass auch Sie die moderne Template-Programmierung meistern und die Welt der Optimierung jenseits aller Grenzen genießen können.&lt;/p></description></item></channel></rss>