<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Concepts on kenji.blog</title><link>http://kenji.blog/ar/tags/concepts/</link><description>Recent content in Concepts on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>ar</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 14:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/ar/tags/concepts/index.xml" rel="self" type="application/rss+xml"/><item><title>إجراء حسابات وقت الترجمة باستخدام البرمجة الوصفية للقوالب في C++</title><link>http://kenji.blog/ar/p/cpp-template-metaprogramming-compile-time-computation/</link><pubDate>Sat, 12 Sep 2026 14:00:00 +0900</pubDate><guid>http://kenji.blog/ar/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 إجراء حسابات وقت الترجمة باستخدام البرمجة الوصفية للقوالب في C++" />&lt;p>من أكبر عوامل الجذب في لغة C++، وفي نفس الوقت من أكثر الجوانب تعقيدًا، هو &amp;ldquo;البرمجة الوصفية للقوالب&amp;rdquo; (Template Metaprogramming: TMP). إنها تقنية تتيح تقديم العمليات الحسابية التي تتم عادةً أثناء وقت التشغيل (Run-time) ليتم تنفيذها مسبقًا أثناء وقت الترجمة (Compile-time)، وذلك عندما يقوم المترجم (compiler) بتحليل كود المصدر لإنشاء الملفات الثنائية (binary).&lt;/p>
&lt;p>في هذا المقال، سنشرح بالتفصيل الممل التطور التاريخي لكيفية اكتساب قوالب C++ لقدراتها الحسابية، بدءًا من SFINAE الكلاسيكي، ومرورًا بـ &lt;code>constexpr&lt;/code> الحديثة و &lt;code>if constexpr&lt;/code>، وصولًا إلى &lt;code>consteval&lt;/code> و Concepts (المفاهيم) في C++20. وسنقدم ذلك مع أمثلة برمجية عملية وخلفية رياضية.&lt;/p>
&lt;hr>
&lt;h2 id="1-فجر-البرمجة-الوصفية-للقوالب-اكتشاف-اكتمال-تورنغ-بالصدفة">1. فجر البرمجة الوصفية للقوالب: اكتشاف اكتمال تورنغ بالصدفة
&lt;/h2>&lt;h3 id="11-ما-هو-اكتمال-تورنغ-turing-completeness">1.1 ما هو اكتمال تورنغ (Turing Completeness)؟
&lt;/h3>&lt;p>في علوم الحاسب، أن يكون النظام &amp;ldquo;مكتمل تورنغ&amp;rdquo; (Turing Complete) يعني أن لديه نفس القدرة الحسابية لآلة تورنغ الشاملة. ببساطة، هو نظام يمكنه تمثيل &amp;ldquo;التفرع الشرطي&amp;rdquo; و&amp;quot;الحلقات اللانهائية (أو الاستدعاء الذاتي)&amp;quot;، وبالتالي يمكنه كتابة وتنفيذ أي خوارزمية.&lt;/p>
&lt;h3 id="12-اكتشاف-إروين-أونرو">1.2 اكتشاف إروين أونرو
&lt;/h3>&lt;p>في عام 1994، خلال اجتماع للجنة توحيد معايير C++، قدم شخص يُدعى إروين أونرو (Erwin Unruh) كود C++. كان هذا الكود يفشل في الترجمة، ولكن والمفاجأة كانت أن &lt;strong>رسائل الخطأ الناتجة عن المترجم كانت تحتوي على سلسلة من الأعداد الأولية&lt;/strong>.&lt;/p>
&lt;p>كان المترجم يقوم بمعالجة عودية (recursive) أثناء عملية استنساخ القوالب (instantiation)، ويُخرج نتيجة تلك الحسابات كرسائل خطأ. لقد كانت تلك اللحظة التي أُثبت فيها أن ميزة القوالب في C++ تحتوي على &lt;strong>نظام حسابي مكتمل تورنغ&lt;/strong> لم يكن مقصودًا حتى من قبل مصمم اللغة، بيارن ستروستروب.&lt;/p>
&lt;hr>
&lt;h2 id="2-البرمجة-الوصفية-للقوالب-الكلاسيكية-c98--c03">2. البرمجة الوصفية للقوالب الكلاسيكية (C++98 / C++03)
&lt;/h2>&lt;p>في البدايات، اتخذت البرمجة الوصفية للقوالب أسلوب برمجة وظيفية خالصة، معتمدة على الهياكل (&lt;code>struct&lt;/code>) وتخصيص القوالب (Template Specialization).&lt;/p>
&lt;h3 id="21-حساب-المضروب-factorial">2.1 حساب المضروب (Factorial)
&lt;/h3>&lt;p>دعونا نلقي نظرة أولاً على المثال الأساسي وهو حساب المضروب ($N!$). رياضيًا، يُعرّف كما يلي:&lt;/p>
$$
N! =
\begin{cases}
1 &amp; (N = 0) \\
N \times (N - 1)! &amp; (N > 0)
\end{cases}
$$&lt;p>عند كتابة هذا باستخدام قوالب C++98، سيكون كالتالي:&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">// القالب الأساسي (الحالة العامة للاستدعاء الذاتي)
&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">// تخصيص صريح للقالب (الحالة الأساسية للاستدعاء الذاتي)
&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">// يُحسب في وقت الترجمة ويُضمن كقيمة ثابتة
&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>النقطة المهمة هنا هي أن &lt;code>Factorial&amp;lt;5&amp;gt;::value&lt;/code> لا يُحسب وقت التشغيل، بل يتم فكه وقت الترجمة. في الملف الثنائي النهائي، يتم إنشاء كود يعادل &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>. وهذا يعني أن التكلفة الإضافية (overhead) أثناء التشغيل تساوي صفرًا.&lt;/p>
&lt;h3 id="22-متتالية-فيبوناتشي-والتعقيد-الحسابي">2.2 متتالية فيبوناتشي والتعقيد الحسابي
&lt;/h3>&lt;p>بعد ذلك، لنحسب متتالية فيبوناتشي. العلاقة التكرارية هي كالتالي:&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>إذا كُتب هذا التنفيذ كدالة عودية وقت التشغيل، فإنه سيكرر نفس الحسابات عدة مرات، مما يجعل التعقيد الحسابي أسيًا $O(2^N)$. ولكن، &lt;strong>أثناء استنساخ القوالب في وقت الترجمة، يتم استنساخ النوع الذي يمتلك نفس وسائط القالب مرة واحدة فقط&lt;/strong> (تأثير يشبه الحفظ أو Memoization). لذلك، فإن التعقيد الحسابي وقت الترجمة يصبح فعليًا $O(N)$.&lt;/p>
&lt;p>يوضح الشكل التالي كيف يقوم المترجم بحل النسخ:&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>في الشكل أعلاه، يتم استنساخ &lt;code>Fib&amp;lt;2&amp;gt;&lt;/code> الذي يحمل نفس اللون أو الشكل مرة واحدة فقط داخل المترجم، وفي المرات اللاحقة يتم استخدام تعريف النوع المخبأ (cached).&lt;/p>
&lt;hr>
&lt;h2 id="3-sfinae-وسمات-النوع-type-traits-c11">3. SFINAE وسمات النوع (Type Traits) (C++11)
&lt;/h2>&lt;p>مع تطور البرمجة الوصفية، أصبحت &amp;ldquo;معالجة وتقييم الأنواع&amp;rdquo; لا تقل أهمية عن &amp;ldquo;حساب القيم&amp;rdquo;. وهنا يظهر مصطلح &lt;strong>SFINAE&lt;/strong> (Substitution Failure Is Not An Error: فشل الاستبدال ليس خطأ).&lt;/p>
&lt;h3 id="31-آلية-عمل-sfinae">3.1 آلية عمل SFINAE
&lt;/h3>&lt;p>أثناء تحليل التحميل الزائد (overload resolution) لدوال القوالب، يستنتج المترجم وسائط القالب من الوسائط المُمررة، ويستبدل الأنواع في توقيع الدالة. في هذه المرحلة، إذا حدث تعارض في الأنواع وفشل الاستبدال، فلن يقوم المترجم بإصدار خطأ ترجمة فورًا، بل سيقوم بـ &lt;strong>استبعاد هذا المرشح للتحميل الزائد بهدوء&lt;/strong> ويبحث عن المرشح التالي.&lt;/p>
&lt;pre class="mermaid">
stateDiagram-v2
[*] --&amp;gt; A
A[&amp;#34;استدعاء دالة القالب&amp;#34;] --&amp;gt; B[&amp;#34;استنتاج النوع&amp;#34;]
B[&amp;#34;استنتاج النوع&amp;#34;] --&amp;gt; C[&amp;#34;استبدال التوقيع&amp;#34;]
C[&amp;#34;استبدال التوقيع&amp;#34;] --&amp;gt; D[&amp;#34;هل نجح الاستبدال؟&amp;#34;]
D[&amp;#34;هل نجح الاستبدال؟&amp;#34;] --&amp;gt; E[&amp;#34;إضافته إلى المرشحين&amp;#34;] : نعم (Yes)
D[&amp;#34;هل نجح الاستبدال؟&amp;#34;] --&amp;gt; F[&amp;#34;استبعاده من المرشحين بدلاً من الخطأ (SFINAE)&amp;#34;] : لا (No)
E[&amp;#34;إضافته إلى المرشحين&amp;#34;] --&amp;gt; G[&amp;#34;تحليل التحميل الزائد&amp;#34;]
F[&amp;#34;استبعاده من المرشحين بدلاً من الخطأ (SFINAE)&amp;#34;] --&amp;gt; G[&amp;#34;تحليل التحميل الزائد&amp;#34;]
G[&amp;#34;تحليل التحميل الزائد&amp;#34;] --&amp;gt; [*]
&lt;/pre>
&lt;h3 id="32-الترجمة-المشروطة-باستخدام-stdenable_if">3.2 الترجمة المشروطة باستخدام std::enable_if
&lt;/h3>&lt;p>باستخدام الترويسة &lt;code>&amp;lt;type_traits&amp;gt;&lt;/code> و &lt;code>std::enable_if&lt;/code> اللتين تم تقديمهما في C++11، يمكنك تفعيل دوال معينة فقط للأنواع التي تستوفي شروطًا محددة.&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">// تفعيل التحميل الزائد فقط إذا كان T نوعًا صحيحًا
&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">// تفعيل التحميل الزائد فقط إذا كان T نوعًا فاصلة عائمة
&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;); // خطأ في الترجمة: لا توجد دالة مطابقة
&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>كان هذا النهج قويًا للغاية، ولكن الصياغة مثل &lt;code>typename std::enable_if&amp;lt;...&amp;gt;::type&lt;/code> كانت مطولة جدًا، مما جعل البعض يتجنب البرمجة الوصفية في C++ معتبرين إياها &amp;ldquo;كرموز مشفرة&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="4-التحول-الجذري-إدخال-constexpr-c11c14">4. التحول الجذري: إدخال constexpr (C++11/C++14)
&lt;/h2>&lt;p>في C++11، تم إدخال الكلمة المفتاحية &lt;code>constexpr&lt;/code>، والتي تُعد ثورة في تاريخ البرمجة الوصفية. وبفضلها، أصبح من الممكن &lt;strong>إجراء حسابات وقت الترجمة باستخدام صياغة الدوال العادية&lt;/strong>، دون الحاجة إلى اللجوء إلى التكرار غير الطبيعي في القوالب.&lt;/p>
&lt;h3 id="41-constexpr-في-c11">4.1 constexpr في C++11
&lt;/h3>&lt;p>دوال &lt;code>constexpr&lt;/code> في إصدار C++11 كانت تخضع لقيد صارم: &amp;ldquo;يجب أن يتكون جسم الدالة من تعليمة &lt;code>return&lt;/code> واحدة فقط&amp;rdquo;. ولذلك، لم يكن بالإمكان استخدام الحلقات، بل كان يجب الاعتماد على المعامل الثلاثي والاستدعاء الذاتي.&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">// فيبوناتشي بـ constexpr في C++11
&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-تخفيف-قيود-constexpr-في-c14">4.2 تخفيف قيود constexpr في C++14
&lt;/h3>&lt;p>في C++14، تم تخفيف هذا القيد بشكل كبير، حيث أصبح من الممكن استخدام تعريف المتغيرات المحلية، وعبارات &lt;code>if&lt;/code>، وحلقات &lt;code>for&lt;/code> داخل دوال &lt;code>constexpr&lt;/code>. أتاح هذا كتابة الخوارزميات بشكل مباشر وبنفس الطريقة المستخدمة في وقت التشغيل.&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">// فيبوناتشي بـ constexpr في C++14
&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>يتم حساب هذا الكود في وقت الترجمة إذا كان التقييم ممكنًا في ذلك الوقت، أما إذا مُررت المتغيرات أثناء وقت التشغيل، فسيتم حسابها كدالة عادية وقت التشغيل.&lt;/p>
&lt;pre class="mermaid">
graph TD
subgraph &amp;#34;وقت الترجمة (Compile Time)&amp;#34;
A[&amp;#34;تحليل كود المصدر&amp;#34;] --&amp;gt; B[&amp;#34;بناء شجرة بناء الجملة المجردة (AST)&amp;#34;]
B[&amp;#34;بناء شجرة بناء الجملة المجردة (AST)&amp;#34;] --&amp;gt; C[&amp;#34;تقييم دوال constexpr&amp;#34;]
C[&amp;#34;تقييم دوال constexpr&amp;#34;] --&amp;gt; D[&amp;#34;تضمين الثوابت (مثل 120)&amp;#34;]
end
subgraph &amp;#34;وقت التشغيل (Runtime)&amp;#34;
E[&amp;#34;بدء تشغيل البرنامج&amp;#34;] --&amp;gt; F[&amp;#34;استخدام النتائج المحسوبة مسبقًا مباشرة&amp;#34;]
F[&amp;#34;استخدام النتائج المحسوبة مسبقًا مباشرة&amp;#34;] --&amp;gt; G[&amp;#34;تنفيذ بدون تكلفة حسابية (تكلفة صفرية)&amp;#34;]
end
D[&amp;#34;تضمين الثوابت (مثل 120)&amp;#34;] --&amp;gt; E[&amp;#34;بدء تشغيل البرنامج&amp;#34;]
&lt;/pre>
&lt;hr>
&lt;h2 id="5-إتقان-التفرع-الشرطي-الثابت-if-constexpr-c17">5. إتقان التفرع الشرطي الثابت: if constexpr (C++17)
&lt;/h2>&lt;p>قدمت C++17 ميزة &lt;code>if constexpr&lt;/code>، التي جعلت التحميل الزائد المعقد باستخدام SFINAE شيئًا من الماضي. إنها عبارة &lt;code>if&lt;/code> تُقيّم في وقت الترجمة، والكتل التي يكون شرطها &lt;code>false&lt;/code> لا يتم استنساخها على الإطلاق، بل يتم تجاهلها تمامًا من عملية الترجمة.&lt;/p>
&lt;p>إذا أعدنا كتابة مثال SFINAE السابق باستخدام &lt;code>if constexpr&lt;/code>، سيصبح بسيطًا بشكل مذهل.&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>باستخدام &lt;code>if constexpr&lt;/code>، يمكن تجميع المعالجات الخاصة بالأنواع المختلفة داخل نفس قالب الدالة، مما أدى إلى تحسين قابلية قراءة الكود بشكل كبير.&lt;/p>
&lt;hr>
&lt;h2 id="6-جوهر-c-الحديثة-consteval-و-concepts-c20">6. جوهر C++ الحديثة: consteval و Concepts (C++20)
&lt;/h2>&lt;p>يعتبر إصدار C++20 تحديثًا هائلاً منذ C++11. وقد شهد مجال البرمجة الوصفية تطورات جذرية فيه أيضًا.&lt;/p>
&lt;h3 id="61-الحساب-الإجباري-في-وقت-الترجمة-consteval">6.1 الحساب الإجباري في وقت الترجمة: consteval
&lt;/h3>&lt;p>كانت &lt;code>constexpr&lt;/code> توجيهًا لـ &amp;ldquo;الحساب وقت الترجمة إذا توفرت الشروط&amp;rdquo;، لكنها تسمح أيضًا بالتقييم وقت التشغيل. على النقيض من ذلك، تُعرِّف &lt;code>consteval&lt;/code>، التي أضيفت في C++20، &lt;strong>دالة فورية (Immediate Function) &amp;ldquo;يجب أن تُقيّم في وقت الترجمة&amp;rdquo;&lt;/strong>. أي محاولة لتقييمها في وقت التشغيل ستؤدي إلى خطأ في الترجمة.&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">// فرض الحساب في وقت الترجمة
&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): تقييم وقت الترجمة
&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); // خطأ: x متغير وقت تشغيل لذا لا يمكن تقييمه
&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-توضيح-متطلبات-القوالب-المفاهيم-concepts">6.2 توضيح متطلبات القوالب: المفاهيم (Concepts)
&lt;/h3>&lt;p>من أكبر نقاط ضعف البرمجة الوصفية كانت &amp;ldquo;صعوبة فهم رسائل الخطأ&amp;rdquo;. عند تمرير نوع خاطئ إلى وسيط القالب، قد يُصدر المترجم مئات الأسطر من الأخطاء غير المفهومة.&lt;/p>
&lt;p>باستخدام &lt;strong>المفاهيم (Concepts)&lt;/strong> في C++20، يمكنك تحديد القيود المفروضة على الأنواع التي يقبلها القالب بطريقة تشبه اللغة الطبيعية، وتصبح رسائل الخطأ واضحة للغاية.&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">// يتطلب أن يكون النوع T نوعًا صحيحًا (integral)
&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; // خطأ: لا يستوفي متطلبات std::integral
&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-مثال-عملي-التحقق-من-الأعداد-الأولية-في-وقت-الترجمة-وتحسين-الخوارزمية">7. مثال عملي: التحقق من الأعداد الأولية في وقت الترجمة وتحسين الخوارزمية
&lt;/h2>&lt;p>لنقم بجمع كل المعرفة التي اكتسبناها لكتابة كود يتحقق من الأعداد الأولية في وقت الترجمة. سنستخدم هنا ميزة C++20 الحديثة (&lt;code>consteval&lt;/code>).&lt;/p>
&lt;p>التعقيد الزمني لخوارزمية التحقق من الأعداد الأولية هو $O(N)$ بالطريقة البسيطة، ولكن يكفي الفحص حتى $\sqrt{N}$، لذا فإن الخوارزمية المثلى ستكون بتعقيد $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">// دالة مساعدة لحساب الجزء الصحيح للجذر التربيعي في وقت الترجمة
&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">// التحقق من العدد الأولي باستخدام 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">// يتم تقييمها بالكامل في وقت الترجمة
&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>في الكود أعلاه، كلا الدالتين &lt;code>compile_time_sqrt&lt;/code> و &lt;code>is_prime&lt;/code> محددتان بـ &lt;code>consteval&lt;/code>، لذا تكتمل هذه الحسابات بنسبة 100% في وقت الترجمة. كل ما يُضمَّن في الملف الثنائي التنفيذي هو مجرد ثوابت منطقية (Boolean) كـ &lt;code>true&lt;/code> أو &lt;code>false&lt;/code>.&lt;/p>
&lt;h3 id="71-التعبير-الرياضي-للتعقيد-الحسابي">7.1 التعبير الرياضي للتعقيد الحسابي
&lt;/h3>&lt;p>في التحقق من الأعداد الأولية، أقصى قيمة يجب فحصها هي $\lfloor \sqrt{N} \rfloor$.
بالتالي، وقت الحساب في أسوأ الحالات $T(N)$ يكون كما يلي:&lt;/p>
$$
T(N) = O(\sqrt{N})
$$&lt;p>إذا تم حساب ذلك في وقت التشغيل، فقد يؤدي إلى تأخير يتراوح بين مئات الميلي ثانية إلى ثوانٍ، خاصة في المعالجات التشفيرية أو تهيئة المحاكاة واسعة النطاق. ومع ذلك، عند استخدام البرمجة الوصفية في وقت الترجمة، يتحمل المترجم هذه التكلفة $T(N)$ بالكامل، وتصبح تكلفة التنفيذ الفعلي على المستخدم $O(1)$.&lt;/p>
&lt;hr>
&lt;h2 id="8-النور-والظل-في-حسابات-وقت-الترجمة">8. النور والظل في حسابات وقت الترجمة
&lt;/h2>&lt;p>على الرغم من أننا رأينا قوة حسابات وقت الترجمة في C++ حتى الآن، إلا أنه لا ينبغي الإفراط في استخدامها دون قيود.&lt;/p>
&lt;h3 id="الإيجابيات-المزايا">الإيجابيات (المزايا)
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>بدون تكلفة إضافية في وقت التشغيل (Zero Overhead)&lt;/strong>: نظرًا لأنه يتم تحويل نتائج العمليات الحسابية إلى ثوابت، فإن سرعة التنفيذ تكون في أقصى حدودها.&lt;/li>
&lt;li>&lt;strong>الاكتشاف المبكر للأخطاء&lt;/strong>: من خلال دمجها مع &lt;code>static_assert&lt;/code> وما شابه، يمكن التقاط أخطاء المنطق أو عدم توافق الأنواع بشكل مؤكد في مرحلة الترجمة.&lt;/li>
&lt;/ul>
&lt;h3 id="السلبيات-العيوب">السلبيات (العيوب)
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>انفجار في وقت البناء (Build Time)&lt;/strong>: العمليات الحسابية داخل المترجم تتم في بيئة مفسر مخصصة (مُقيِّم AST الخاص بالمترجم)، مما يجعلها أبطأ بكثير من تنفيذ الكود الأصلي (native code) وقت التشغيل. إجراء حسابات ضخمة، كحسابات المصفوفات الكبيرة، في وقت الترجمة قد يؤدي إلى تضخم وقت البناء ليصل إلى عدة ساعات.&lt;/li>
&lt;li>&lt;strong>تضخم الملف الثنائي (Code Bloat)&lt;/strong>: عندما يتم استنساخ القوالب لأنواع متعددة ومختلفة، تتولد العديد من الدوال مما قد يتسبب في زيادة حجم الملف التنفيذي بشكل كبير.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="9-الخاتمة">9. الخاتمة
&lt;/h2>&lt;p>بدأت البرمجة الوصفية للقوالب في C++ كـ &amp;ldquo;نتاج صدفة (هاك)&amp;rdquo; حيث تم إخراج الأعداد الأولية من رسائل الخطأ، ومن خلال سنوات من العمل على التوحيد القياسي، تطورت إلى ميزات لغوية مصقولة ومتقدمة (&lt;code>constexpr&lt;/code>، &lt;code>if constexpr&lt;/code>، و &lt;code>Concepts&lt;/code>).&lt;/p>
&lt;p>في لغة C++ الحديثة، انخفض حاجز مصطلح &amp;ldquo;البرمجة الوصفية&amp;rdquo; بشكل جذري، وأصبح من الممكن الاستفادة من مزايا الحسابات في وقت الترجمة أثناء كتابة كود بديهي تمامًا كما نفعل في البرمجة العادية.&lt;/p>
&lt;p>ستظل هذه التقنية سلاحًا لا غنى عنه مستقبلاً في الأنظمة التي تتطلب أداءً فائقًا، كالأنظمة المدمجة، محركات الألعاب، وأنظمة التداول عالي التردد (HFT).&lt;/p>
&lt;p>لا يزال تطور C++ مستمرًا. في المعايير القادمة مثل C++23 و C++26، هناك ميزات أكثر قوة تلوح في الأفق مثل الانعكاس في وقت الترجمة (Compile-time Reflection). ندعوكم جميعًا لإتقان برمجة القوالب الحديثة، والاستمتاع بعالم التحسينات التي تتجاوز كل الحدود.&lt;/p></description></item></channel></rss>