أكثر ما أراه في أكواد المحترفين في ++C هو استخدامهم للــtemplates بشكل يثير الفضول !
لطالما حاولت قصر فهمي لها بأنه تأخذ وسيطاً بين<> وهو اسم النوع الذي نتعامل معه ... ولكنها كانت أروع من ذلك بكثيير !
في البداية كنت أحب استخدام #define فهي لغة بداخل اللغة وكان هذا ممتعاً .. أنت تكتب كود يغيّر نفسه ..
ولكن وظيفة #define مقتصرة على استبدال معرّف ما بعبارة معيّنة , الاستبدال فقط .. لا يوجد توليد لأي شيء ..
بعد نظرتين وثلاث .. ولمحتها بالصدفة عدّة مرات .. لم أستطع مقاومة قراءة هذا الكود للأخ خالد في تلك المشاركة ..
وأخيراً .. كلّمتني :) ... فهمتها .. وعلى الفور خطرت ببالي فكرة مرعبة ..
#include<cstdio>
template<int a>
bool hello()
{
//Hello World!
if(a>1)
if(a==2||a==3||a==5||a==7||a==11||a==13||a==17||a==19)
if(a%2!=0&&a%3!=0&&a%5!=0&&a%7!=0&&a%11!=0&&a%13!=0&&a%17!=0&&a%19!=0)
return true;
return false;
}
int main()
{
printf("%i\n",hello<17*17+1>());
return 0;
}لما طبّقتها ..نجحت .. وقررت الخوض في الحديث .. يعني الكود التالي :template<int a,int b>
bool hello2()
{
if(a==b)
return 1;
if(a%b==0)
return 0;
return hello2<a,b+1>();
}
int main()
{
hello2<27,2>();
return 0;
}لكن ما حصل نصيب ! , يا أخي شيء عجيب ! لي بضعة أيام ,المصرّف يعرّفني على كل الأخطاء الموجودة عنده .. قالfatal error C1202: recursive type or function dependency context too complexحاولنا مع واسطة
template<int a,int b>
bool hello2()
{
if(a==(a-b))
return 1;
if(a%(a-b)==0)
return 0;
return hello2<a,b-1>();
}
template<>bool hello2<27,1>(){return true;}
template<>bool hello2<97,1>(){return true;}
#include<iostream>
using namespace std;
int main()
{
cout<<hello2<97,97-2>()<<endl;
cout<<hello2<27,27-2>()<<endl;
return 0;
}وبالفعل نجحت العودية .. لكن ليس هذا مطلبي !لا أريد أن بتم الاستدعاء في الـ runtime .. أريد النتيجة جاهزة أول ما يشتغل الأخ البرنامج ! أريد أن تُحسب النتيجة في وقت التصريف Compile time.
المصرّف يقوم بما يلي :
هل هناك استدعاء لدالة template ؟ هات الوسطاء وخلّيني أنشئ دالة لهذا الاستدعاء
يعني السحر فقط بإنشاء دوال جديدة لكل استدعاء مختلف
الأخ Erwin Unruh هو أول من كتب كود meta programming
// Prime number computation by Erwin Unruh
template <int i>
struct D
{
D(void*);
operator int();
};
template <int p, int i>
struct is_prime
{
enum { prim = (p%i) && is_prime<(i > 2 ? p : 0), i -1> :: prim };
};
template < int i >
struct Prime_print
{
Prime_print<i-1> a;
enum { prim = is_prime<i, i-1>::prim };
void f() {
D<i> d = prim;
}
};
struct is_prime<0,0> { enum {prim=1}; };
struct is_prime<0,1> { enum {prim=1}; };
struct Prime_print<2> {
enum {prim = 1};
void f() { D<2> d = prim; }
};
#ifndef LAST
#define LAST 10
#endif
main () {
Prime_print<LAST> a;
}صحيح أن الكود لم يعمل عندي كما يٌفترض به ( يعمل الكود بأن لا يعمل ولكن بطريقة احترافية يُفترض به أن يصدر errors تشير إلى رقم السطر الذي حدث فيه الخطأ , وأن تكون أرقام الأأسطر التي تسببت بالخطأ أوّليّة)ولكن لاحظت به عدّة أمور : enum ,و struct!! هذه أيضاً ما كنت أرفع عيني لأراها .. أنت يا enum .. جلست أسمع قصّتها .. ومعنا struct
وجرى بيننا الحوار التالي :
#include<cstdio>
template<int a,int b>
struct mosty
{
static enum {fofo=(a%b==0)?0:mosty<a,b+1>::fofo};
};
template<int a>struct mosty<a,a>
{
static enum {fofo=1 };
};
int main()
{
printf("3 %i\n",mosty<3,2>::fofo);
printf("4 %i\n",mosty<4,2>::fofo);
printf("5 %i\n",mosty<5,2>::fofo);
printf("6 %i\n",mosty<6,2>::fofo);
printf("7 %i\n",mosty<7,2>::fofo);
printf("8 %i\n",mosty<8,2>::fofo);
printf("9 %i\n",mosty<9,2>::fofo);
printf("10 %i\n",mosty<10,2>::fofo);
printf("11 %i\n",mosty<11,2>::fofo);
printf("12 %i\n",mosty<12,2>::fofo);
printf("13 %i\n",mosty<13,2>::fofo);//الحب من النظرة 13
return 0;
}ويا للعجب :) نجحت أخيراً ... قمت بكتابة أول MetaProgram ناجح .. وتم اختبار أولية العدد أثناء وقت التصريف compile time .وعندما حاولت الذهاب بها بعيداً
printf("13 %i\n",mosty<1313,2>::fofo);انفجر الأب compiler :D في وجهي ..fatal error C1001: An internal error has occurred in the compiler.وكانت هذه آخر مرة نتحدث فيها عن الموضوع .
0x36a2