• 0
مصطفى 36a2

الحب من النظرة 13 ... Meta Programming

سؤال

أكثر ما أراه في أكواد المحترفين في ++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 Unruhtemplate <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#endifmain () {    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

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

36 إجابة على هذا السؤال .

  • 0

إليك هذا الكود للتسلية:

#include <iostream>using std::cout;using std::endl;typedef   signed long long int  int64_t;typedef unsigned long long int uint64_t;template<uint64_t val>struct log2_for_literal{	static const int64_t value = 1 + log2_for_literal< (val >> 1) >::value;};template<> struct log2_for_literal<1> { static const int64_t value = 0; };template<typename t, uint64_t p>struct power10_for_type_helper{	static const t value = 10 * power10_for_type_helper<t, p - 1>::value;};template<typename t> struct power10_for_type_helper<t, 0> { static const t value = 1; };template<uint64_t p>struct power10_for_value{	static const uint64_t value = power10_for_type_helper<uint64_t, p>::value;};template<uint64_t val>struct log10_for_literal{private:	static const int64_t pvalue = int64_t( ((log2_for_literal<val>::value + 1) * 1233) >> 12);public:	static const int64_t value = pvalue - int64_t(val < power10_for_value<pvalue>::value);};template<uint64_t val>struct num_of_dec_digits_in_value{	static const int64_t value = log10_for_literal<val>::value + 1;};int main(){	const int num = 965;	cout << "number of decimal digits in " << num      << " is " << num_of_dec_digits_in_value<num     >::value << endl;	cout << "number of decimal digits in " << num * 7  << " is " << num_of_dec_digits_in_value<num * 7 >::value << endl;	cout << "number of decimal digits in " << num * 13 << " is " << num_of_dec_digits_in_value<num * 13>::value << endl;}

الكود ببساطة يحسب عدد الخانات العشرية برقم، و في مثالنا هذا المفترض ان تكون النتيجة:

number of decimal digits in 965 is 3number of decimal digits in 6755 is 4number of decimal digits in 12545 is 5

و الله ولي التوفيق

تم تعديل بواسطه C++er
1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

جزاك الله خيراً

أرى أن الكود يستخدم تقريباً للوغاريتم الثنائي لم أفهمه ..

ولكن لم كل هذا التعقيد :D

ما رأيك بهذا :)

#include<iostream>using std::cout;using std::endl;template<int a>struct num_of_dec_digits{    static const int value = 1+(num_of_dec_digits<a/10>::value);};template<>struct num_of_dec_digits<0>{static const int value = 1;};template<>struct num_of_dec_digits<1>{static const int value = 1;};template<>struct num_of_dec_digits<2>{static const int value = 1;};template<>struct num_of_dec_digits<3>{static const int value = 1;};template<>struct num_of_dec_digits<4>{static const int value = 1;};template<>struct num_of_dec_digits<5>{static const int value = 1;};template<>struct num_of_dec_digits<6>{static const int value = 1;};template<>struct num_of_dec_digits<7>{static const int value = 1;};template<>struct num_of_dec_digits<8>{static const int value = 1;};template<>struct num_of_dec_digits<9>{static const int value = 1;};int main(){    const int num = 965;    cout << "number of decimal digits in " << num  /100    << " is " << num_of_dec_digits<num /100    >::value << endl;    cout << "number of decimal digits in " << num  /10    << " is " << num_of_dec_digits<num /10    >::value << endl;    cout << "number of decimal digits in " << num      << " is " << num_of_dec_digits<num     >::value << endl;    cout << "number of decimal digits in " << num * 7  << " is " << num_of_dec_digits<num * 7 >::value << endl;    cout << "number of decimal digits in " << num * 13 << " is " << num_of_dec_digits<num * 13>::value << endl;}

جزاك الله خيرا

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

هذا اجمل ما فى البرمجة، اكثر من طريقة لنفس النتيجة.

 

أنظر هذا المثال أيضا:

template<typename t>struct log10_for_type{	static const int64_t value = int64_t( (((sizeof(t) * 8) - ((t(0) > t(-1))? 1: 0)) * 1233) >> 12);};template<typename t>struct power10_for_type{	static const uint64_t value = power10_for_type_helper<t, log10_for_type<t>::value>::value;};int main(){	cout << "maximum 10 power that can be stored in uint8_t  is " << power10_for_type<unsigned char>::value << endl;	cout << "maximum 10 power that can be stored in uint16_t is " << power10_for_type<unsigned short>::value << endl;	cout << "maximum 10 power that can be stored in uint32_t is " << power10_for_type<unsigned int>::value << endl;	cout << "maximum 10 power that can be stored in uint64_t is " << power10_for_type<unsigned long long int>::value << endl;}

و النتيجة:

maximum 10 power that can be stored in uint8_t  is 100maximum 10 power that can be stored in uint16_t is 10000maximum 10 power that can be stored in uint32_t is 1000000000maximum 10 power that can be stored in uint64_t is 10000000000000000000

:D

 

و الله ولي التوفيق

تم تعديل بواسطه C++er
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

:) رائع لدي بعض الأسئلة قبل وضع محاولتي

((t(0) > t(-1))? 1: 0))

هذا اختبار unsigned أليس كذلك :D  رائع ..

بالنسبة للتقريب :

* 1233    >> 12

الضرب بـ 1233 ثم القسمة على 4096 (يعني الضرب بـ  0.301025 وهو اللوغاريتم العشري للـ2) يبدو أنه تقريب ناجح للوغاريتم العشري !

 

هذه محاولتي .. لا أحب التعقيد ×_×

#include<iostream>using std::cout;using std::endl;typedef unsigned long long int  ulli;template<typename x , int y>struct Xpower10_for_type{    const static ulli value = ulli(10) * Xpower10_for_type<x,y/10>::value;};template<typename x >struct Xpower10_for_type<x,0>{    const static ulli value = 1;};template<typename x >struct power10_for_type{    const static ulli value = Xpower10_for_type < x , x(-1) >::value / 10 ;};int main(){    cout << "maximum 10 power that can be stored in uint8_t  is " << power10_for_type<unsigned char>::value << endl;    cout << "maximum 10 power that can be stored in uint16_t is " << power10_for_type<unsigned short>::value << endl;    cout << "maximum 10 power that can be stored in uint32_t is " << power10_for_type<unsigned int>::value << endl;    cout << "maximum 10 power that can be stored in uint64_t is " << power10_for_type<unsigned long long int>::value << endl;return 0;}

ولكن هناك خطأ لا أدري سببه , فالعملية لا تتم على int وعلى long long !! لماذا ؟

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

الخطأ لديك يكمن فى هذا السطر:

template<typename x , int y>

فلك ان تتخيل ماذا سيحدث عن يتم تمرير قيمة ulli(-1)/2 حينها سيحدث overflow و لن يتم ترميز القيمه بشكل سليم. للحل اجعل x من نوع ulli.

 

حتى الأن سيتم الحصول على النتيجة بشكل سليم ما عدا النوع ulli، و انا اعرف السبب و لكن ساتركك تفكر فيه قليلا.

 

هذه محاولتي .. لا أحب التعقيد ×_×

أنا ايضا لا احب التعقيد و لكن هذا الكود هو جزء صغير من مجموعة اكواد كبيرة يتم استخدامها فى اكثر من مكان داخل مكتبة صممتها و بالنسبة لحجم المشروع فهذا هو الجزء اليسير.

 

 

و الله ولي التوفيق

2

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

نعم بالضبط .. الوسيط y يجب أن يكون ulli

 

بالنسبة للخطأ الثاني فقد عرفت السبب , فالعدد 7766279631452241920 هو 10^21 % 18446744073709551616 أي أنني تجاوزت القيمة المسموحة عند الضرب بـ 10 ..

وأظن أن هذا يحلّ المشكلة :

#include<iostream>using std::cout;using std::endl;typedef unsigned long long int  ulli;template<typename x , ulli y>struct Xpower10_for_type{    const static ulli value = ulli(10) * Xpower10_for_type<x,y/10>::value;};template<typename x >struct Xpower10_for_type<x,0>{const static ulli value = 1;};template<typename x >struct Xpower10_for_type<x,1>{const static ulli value = 1;};template<typename x >struct Xpower10_for_type<x,2>{const static ulli value = 1;};template<typename x >struct Xpower10_for_type<x,3>{const static ulli value = 1;};template<typename x >struct Xpower10_for_type<x,4>{const static ulli value = 1;};template<typename x >struct Xpower10_for_type<x,5>{const static ulli value = 1;};template<typename x >struct Xpower10_for_type<x,6>{const static ulli value = 1;};template<typename x >struct Xpower10_for_type<x,7>{const static ulli value = 1;};template<typename x >struct Xpower10_for_type<x,8>{const static ulli value = 1;};template<typename x >struct Xpower10_for_type<x,9>{const static ulli value = 1;};template<typename x >struct power10_for_type{    const static ulli value = Xpower10_for_type < x , x(-1) >::value  ;};int main(){    cout << "maximum 10 power that can be stored in uint8_t  is " << power10_for_type<unsigned char>::value << endl;    cout << "maximum 10 power that can be stored in uint16_t is " << power10_for_type<unsigned short>::value << endl;    cout << "maximum 10 power that can be stored in uint32_t is " << power10_for_type<unsigned int>::value << endl;    cout << "maximum 10 power that can be stored in uint64_t is " << power10_for_type<unsigned long long int>::value << endl;return 0;} 

 

ولكنني أنزعج بشدة عندما أجد أجزاء مكرّرة في الكود .. فهذا دليل خطأ أو نقص في جودة التصميم ...

جزاك الله خيراً .. أتمنى لو أتدرب أكثر .. هل هناك أفكار تجدها صعبة التحقيق ؟ بصراحة أنا أهتم بإيجاد الحل أكثر من الاهتمام بفهم باقي الحلول ... يعني طالما يمكنني الحل بطريقة معينة فلن أهتم بباقي الطرق ..

فهل هناك مسألة تفكّر فيها .. وترى أنني سأضطر للاستسلام بعدها :D ؟

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0
ولكنني أنزعج بشدة عندما أجد أجزاء مكرّرة في الكود .. فهذا دليل خطأ أو نقص في جودة التصميم ...

أحيانا تكرار الكود افضل من وضع خورازمية معقدة لأنه مع مرور الوقت يزداد الإعتماد على الكود المكتوب و يصعب تغيير و انما الأسهل تطويره، لذا فلأول يسهل إبداله و تغييره أما الأخير فلن يكون سهل التطوير.

 

فهل هناك مسألة تفكّر فيها .. وترى أنني سأضطر للاستسلام بعدها :D ؟

هل تعتقد ان ما وضعته صعب، تذكر ما قلته لك فى البداية:

إليك هذا الكود للتسلية

 

التعقيد لم يأتي بعد و الكود التالي هو تعديل على الكود الأصلي لك لتجاوز مشكلة الـ overflow:

#include<iostream>using std::cout;using std::endl;typedef unsigned long long int  ulli;template<typename x , ulli y>struct Xpower10_for_type{    const static ulli value = ulli(10) * Xpower10_for_type<x,y/10>::value;};template<typename x >struct Xpower10_for_type<x,0>{    const static ulli value = 1;};template<typename x >struct power10_for_type{    const static ulli value = Xpower10_for_type < x , (x(-1) >> 1) >::value / ((x(~0) >= ~0ull)? 1: 10);};int main(){    cout << "maximum 10 power that can be stored in uint8_t  is " << power10_for_type<unsigned char>::value << endl;    cout << "maximum 10 power that can be stored in uint16_t is " << power10_for_type<unsigned short>::value << endl;    cout << "maximum 10 power that can be stored in uint32_t is " << power10_for_type<unsigned int>::value << endl;    cout << "maximum 10 power that can be stored in uint64_t is " << power10_for_type<unsigned long long int>::value << endl;return 0;}

التعديل الذى قمت به ستجد داخل power10_for_type.

 

إليك سؤال ذات مستوى متوسط:

 

تخيل ان لدينا نوع unsigned بأى مساحة و قمنا بتخزين داخله اكبر قيمة يمكن ترميزها به. عند تحويل هذه القيمه للنظام الثماني ستلاحظ شئ و هو ان اخر رقم من ناحية اليسار إما واحد او ثلاثة و البقية 7، المطلوب منك هو معرفة عدد الخانات التى تحتوى على 7 و قيمة الخانة الأخيرة فقط بإعطائك مساحة النوع بالبايت مع العلم ان المساحة دائما من مضاعفات الرقم 2.

 

أيضا ايا كان نظام التشغيل الخاص بك سنفترض ان CHAR_BIT تساوى 8.

 

الكود النهائي لك المفترض ان يكون كالتالي:

#include <iostream>using std::cout;using std::endl;typedef unsigned int uint32_t;template<uint32_t size>struct left_most_oct_digit{    static const uint32_t value = ?;};template<uint32_t size>struct oct_seven_count{    static const uint32_t value = ?;};int main(){	cout << "in type with size " << sizeof(unsigned char) << " byte(s):\n";	cout << "\tleft-most octal digit is " << left_most_oct_digit<sizeof(unsigned char)>::value << "\t\n";	cout << "\tseven digit count is " << oct_seven_count<sizeof(unsigned char)>::value << "\t\n\n";	cout << "in type with size " << sizeof(unsigned long long) << " byte(s):\n";	cout << "\tleft-most octal digit is " << left_most_oct_digit<sizeof(unsigned long long)>::value << "\t\n";	cout << "\tseven digit count is " << oct_seven_count<sizeof(unsigned long long)>::value << "\t\n\n";		cout << "in type with size " << 1024 << " byte(s):\n";	cout << "\tleft-most octal digit is " << left_most_oct_digit<1024>::value << "\t\n";	cout << "\tseven digit count is " << oct_seven_count<1024>::value << "\t\n\n";	cout << "in type with size " << 4096 << " byte(s):\n";	cout << "\tleft-most octal digit is " << left_most_oct_digit<4096>::value << "\t\n";	cout << "\tseven digit count is " << oct_seven_count<4096>::value << "\t\n\n";}

قم بإبدال علامة الإستفهام الموجوده داخل left_most_oct_digit و oct_seven_count بالكود الذى تريد و الذى من شأنه عن استدعاء value تنتج لنا قيمة رقمية صحيحة.

 

للعلم الكود يسير.

 

 

و الله ولي التوفيق

تم تعديل بواسطه C++er
1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

بارك الله فيك :)

لا بد أنك كتبت كود الاختبار  بدون أن تجرّبه فنسيت إضافة value:: للاستدعاء ;)

بالنسبة لجزء الــ oct sevens فهو بسيط جدا ولله الحمد

template<uint32_t size>struct oct_seven_count{    static const uint32_t value = 2*size+size/2;};

أما بالنسبة لقسم آخر منزلة .. فقد اضطررت لإضافة قالب آخر .. كما يلي :

template<uint32_t size>struct left_most_oct_digit{    static const uint32_t value = 4-left_most_oct_digit<size/2>::value;};template<>struct left_most_oct_digit<1>{static const uint32_t value = 3;}; 

إذا كان هذا ممنوعاً , فأخبرني حتى أفكّر بشيء آخر ..

 

على كل حال هذا هو الكود كاملاً مع الطريقة التي وصلت بها إلى الحل

#include <iostream>using std::cout;using std::endl;typedef unsigned int uint32_t;template<uint32_t size>struct left_most_oct_digit{    static const uint32_t value = 4-left_most_oct_digit<size/2>::value;};template<>struct left_most_oct_digit<1>{static const uint32_t value = 3;};template<uint32_t size>struct oct_seven_count{    static const uint32_t value = 2*size+size/2;};/*How I did Think ?//1 byte --> FF                        3 and 2 7s--->1*2+0//2 byte --> FFFF                    1 and 5 7s--->2*2+1//4 byte --> FFFF FFFF                3 and 10 7s-->4*2+2//8 byte --> FFFF FFFF FFFF FFFF    1 and 20 7s-->8*2+4*/int main(){    cout << "in type with size " << sizeof(unsigned char) << " byte(s):\n";    cout << "\tleft-most octal digit is " << left_most_oct_digit<sizeof(unsigned char)>::value << "\t\n";    cout << "\tseven digit count is " << oct_seven_count<sizeof(unsigned char)>::value << "\t\n\n";    cout << "in type with size " << sizeof(unsigned long long) << " byte(s):\n";    cout << "\tleft-most octal digit is " << left_most_oct_digit<sizeof(unsigned long long)>::value << "\t\n";    cout << "\tseven digit count is " << oct_seven_count<sizeof(unsigned long long)>::value << "\t\n\n";        cout << "in type with size " << 1024 << " byte(s):\n";    cout << "\tleft-most octal digit is " << left_most_oct_digit<1024>::value << "\t\n";    cout << "\tseven digit count is " << oct_seven_count<1024> ::value<< "\t\n\n";    cout << "in type with size " << 4096 << " byte(s):\n";    cout << "\tleft-most octal digit is " << left_most_oct_digit<4096>::value << "\t\n";    cout << "\tseven digit count is " << oct_seven_count<4096> ::value<< "\t\n\n";return 0;}

جزاك الله خيراً :) وشكرا لوقتك .

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

الإجابة الصحيحة هي:

in type with size 1 byte(s):        left-most octal digit is 3        seven digit count is 2in type with size 8 byte(s):        left-most octal digit is 1        seven digit count is 21in type with size 1024 byte(s):        left-most octal digit is 3        seven digit count is 2730in type with size 4096 byte(s):        left-most octal digit is 3        seven digit count is 10922

إجابتك هي:

in type with size 1 byte(s):        left-most octal digit is 3        seven digit count is 2in type with size 8 byte(s):        left-most octal digit is 1        seven digit count is 20in type with size 1024 byte(s):        left-most octal digit is 3        seven digit count is 2560in type with size 4096 byte(s):        left-most octal digit is 3        seven digit count is 10240

و بالتالي إجابتك خاطئة.

 

إذا كان هذا ممنوعاً , فأخبرني حتى أفكّر بشيء آخر ..

طالما الكود الأصلي موجود و يمكن استدعائه لا مشكلة فى اضافتك اى اكواد اخرى تريد.

 

 

و الله ولي التوفيق

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

لو أنك أعطيتني الأجوبة من البداية لكنت قارنت الحلول :) .. على كل حال كان الخطأ من عد السبعات من الآلة الحاسبة .. اعذرني ..

هذا هو التصحيح

template<uint32_t size>struct oct_seven_count{    static const uint32_t value = 2*oct_seven_count<size/2>::value + !is4power<size>::value;};template<uint32_t size>struct is4power{    static const uint32_t value = !is4power<size/2>::value;};template<>struct is4power<1>{static const uint32_t value = 1;};template<>struct oct_seven_count<1>{static const uint32_t value = 2;};

والآن كل شيء تمام ..

ما هو حلّك للمسألة ؟ هل كان في نفس القالب بدون إضافات ؟ لا أظن ذلك !

 

جزاك الله خيراً :)

1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

انت لا تحب التعقيد اليس كذلك، أنظر التالي:

template<uint32_t size>struct left_most_oct_digit{    static const uint32_t value = ((size*8) % 3 == 1)? 1: 3;};template<uint32_t size>struct oct_seven_count{    static const uint32_t value = (size*8)/3;};

اعتقد ان الحل مفهوم؟

 

يمكنني اعطائك العديد من هذه الأمثلة إن احببت، و رأيي انه حان الوقت لأن تقرأ الكتابين C++ Template Metaprogramming  و C++ Templates - The Complete Guide.

 

 

 

و الله ولي التوفيق

تم تعديل بواسطه C++er
2

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

يظهر لي أنك عاشق للــ Optimal Solutions ...  ما شاء الله ..

أنا ركّزت في القوالب حتى نسيت أفكّر بتبسيط الــ pattern :) بالفعل حلّي معقّد كثيراً ... ولا بد أنه سيفشل في الحالات الكبيرة لاستخدام العوديّة .

 

size*8) % 3) size*8/3

رائعة !

وهذا الإثبات للدلالة على أنني فهمت ..

حسب الــnumber theory وتحديداً modulat arithmatic فإن قوى العدد 4 باقي قسمتها على 3 هو 1 دوماً لأن 4%3==1 ..انتهى الإثبات . ومن الــ pattern الناتج يمكننا استنتاج أن قوى 4 تعطي 3 والباقي يعطي 1 ..

 

بالنسبة للثانية :

 

كانت تحتاج نظرة متأملة في الــ pattern الناتج عن : 8 ...16...32...64 وكل واحدة تقابل ... 2 ...5 ...10 ... 21 ... :D واضحة العلاقة

 

لابد أن الكتب التي نصحتني بها هي الأهم في الــ MetaProgramming

ولكن أرجو إمدادي بمزيد من التمارين .. فالكتب المفتوحة معاً في foxitReader لا تسمح لي ببدء كتاب جديد الآن ..كما أنني لم أقرأ كتاباً في++C حتى الآن ..  أما التفكير فله وقت دائماً ..

 

وانا مستعد لحل المسائل .. :)

ولكن لدي سؤال قبل المتابعة : بالنسبة لكود erwin (اول MP )

.. على أي مترجم أو بيئة يُفترض به أن يعمل ؟ كما أنني لم ألاحظ أن رقم السطر يتغيّر عندما يصدر خطأ خاص بالقالب .. بالعكس كل شيء عادي وفي مكانه !!

 

بانتظار مسألة جديدة ..

 

وشكرا جزيلا لك .

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

بالنسبة لإثبات صحة الطريقة التي كتبتَ بها الحل .. فهذا إثبات رياضي .. لا يعتمد على الملاحظة أو الانتباه للــpattern

 

نعلم أن العد النظام الثنائي يمكن تجميع كل 3 بت منه لتكوّن منزلة في النظام الثماني (انتبه للرقم 3)

ونعلم أن أكبر رقم بالثنائي في عدد بتات معيّن سيكون 1111111...11 وعند تجميعها في فئات من 3 بتات سيكون 7777 ... 77؟ وهذه الـ؟ إما أن تكون 1 أو 11 أو 111 بالثنائي

بصيغة أخرى : بما أننا نجمّع مجموعات من 3بتات فسيبقى في الآخر 1 أو 2 أو 3 بت لنضعها معاً .. ولكن قوى العدد 2 دائماً باقي قسمتها على 3 هو 1 أو 2 لذلك سيتشكل 1 أو 11 وهو 3 بالثماني .

وكما رأينا .. نأخذ عدد البتات ونقسمه على 3 فيعطينا عدد الـ7 في الرقم ..

____________________

إضافة :

بالنسبة لكود Erwin  كنت أقوم بمراجعة فكرته (من هنا تعرفت عليه أول مرة ) عذراً أخطأت .. الكود يولّد أخطاء ويكون العدد الممرّلا للقالب الذي سبب الخطأ أولي .. وليس رقم السطر أولي .. أرجو الانتباه (لن أعدل المشاركات السابقة )

تم تعديل بواسطه مصطفى 36a2
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

بانتظار مسألة جديدة ..

كبداية، اى عضو مرحب به أن يشارك معنا بالحل الخاص به.

 

الأنواع الصحيحة التى تقبل منك الأرقام السالبة و الموجبة تحدد لك مدى معين، المطلوب هو أني إما اعطيك رقم واحد أو مدى مكون من رقمين و تقوم انت بإعطائى النوع الأمثل لتمثيل الرقم.

 

المقصود بالنوع الأمثل اى النوع ذات المساحة الأصغر و الذى يمكنه تمثيل الرقم او المدى بدون اى مشاكل.

 

الانواع التى سنتعامل معها هى:

signed charsigned short intsigned intsigned long long int

و بالنسبة لشكل الكود المفترض ان يكون كالتالي:

#include <iostream>#include <climits>using std::cout;using std::endl;typedef signed char          int8_t;typedef signed short int     int16_t;typedef signed int           int32_t;typedef signed long long int int64_t;template<typename t>struct type_meta{	static const int64_t byte_size = sizeof(t);	static const int64_t bit_size  = sizeof(t) * 8; // you may use sizeof(t) * CHAR_BIT	static const int64_t id        = (byte_size==1)? 1:					 (byte_size==sizeof(int16_t))? 2:					 (byte_size==sizeof(int32_t))? 3:					 (byte_size==sizeof(int64_t))? 4:					 (0);	static const int64_t min_value = (byte_size==1)? SCHAR_MIN:					 (byte_size==sizeof(int16_t))? SHRT_MIN:					 (byte_size==sizeof(int32_t))? INT_MIN:					 (byte_size==sizeof(int64_t))? LLONG_MIN:					 (0);	static const int64_t max_value = (byte_size==1)? SCHAR_MAX:					 (byte_size==sizeof(int16_t))? SHRT_MAX:					 (byte_size==sizeof(int32_t))? INT_MAX:					 (byte_size==sizeof(int64_t))? LLONG_MAX:					 (0);};template<int64_t v1, int64_t v2>struct get_type{	static const int64_t min = (v1>v2)? v2: v1;	static const int64_t max = (v1>v2)? v1: v2;	typedef /* implementation-defined */ type;};template<int64_t v>struct get_type<v, v>{	typedef /* implementation-defined */ type;};template<int64_t v1, int64_t v2 = v1>struct msg{	friend std::ostream& operator<< (std::ostream& stm, const msg<v1, v2>&)	{		typedef type_meta< typename get_type<v1, v2>::type > info;		static const char* type_names[]=		{			"**unkown**",			"signed char",			"signed short int",			"signed int",			"signed long long int"		};		if (v1 == v2)			stm << "optimal type for value [" << v1 << "] is " << type_names[info::id] << endl;		else			stm << "optimal type for range [" << v1 << ", " << v2 << "] is " << type_names[info::id] << endl;		stm << type_names[info::id] << " range is [" << info::min_value << ", " << info::max_value << "]\n\n";		return stm;	}};int main(){	cout << msg<0, 1>();	cout << msg<100, -128>();	cout << msg<SHRT_MIN, INT_MAX>();	cout << msg<SHRT_MIN-1, -1>();	cout << msg<LLONG_MAX, INT_MAX-1>();	cout << msg<-1>();	cout << msg<0>();	cout << msg<SHRT_MAX>();	cout << msg<SHRT_MAX+1>();}

تم تحديد 4 انواع للإستخدام و هم int8_t و int16_t و int32_t و int64_t.

النوع type_meta يعطيك بعض المعلومات عن أى من الأربع انواع السابقة. العنصر id هو رقم يمثل مكان اسم النوع داخل مصفوفة طباعة النتيجة (ستأتي لاحقا).

النوع get_type هو قلب البرنامج حيث يأخذ منك رقمين بأى ترتيب فإذا كان الرقمين متشابهين سيتم إستخدام النسخة المخصصة منه - النسخة الثانية - و إذا كان الرقمين متشابهين سيتم التعامل مع النسخة الأولي و التى تحتوى على الثابتين min و max لأقل قيمة و اكبر قيمة تم إدخالهم.

 

داخل النوع get_type يوجد typedef بالإسم type و قيمة هذا الـ typedef انت من سيحددها تبعا للقيم التى تم تمريرها.

 

النوع msg يأخذ منك مدى الأرقام و يقوم بالحصول على البيانات اللازمة ثم يطبع النتيجة داخل standard stream، أيضا داخليا يحتوى على المصفوفة الخاصة بأسماء الأنواع.

 

مستوى هذا المثال فوق المتوسط و يحتاج تركيز وفهم جيد لمكونات اللغة.

 

 

و الله ولي التوفيق

تم تعديل بواسطه C++er
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

جزاك الله خيراً :)
حللت السؤال بصعوبة .. وبالكاد فهمت على المصرّف ماذا يريد .. وعند إضافة typename اشتغل كل شيء ..
يبدو أنه يحتاج لتأكيد بأن المحتوى هو نوع :)
هذا هو الكود

template <int8_t x>struct Typaminia{typedef int typeName;};template <>struct Typaminia<1>{typedef int8_t typeName;};template <>struct Typaminia<2>{typedef int16_t typeName;};template <>struct Typaminia<3>{typedef int32_t typeName;};template <>struct Typaminia<4>{typedef int64_t typeName;};template <int64_t min,int64_t max>struct Typorium{    static const int8_t typeId=(min<INT_MIN    ||    max>INT_MAX)? 4:                            (min<SHRT_MIN    ||    max>SHRT_MAX)? 3:                            (min<SCHAR_MIN    ||    max>SCHAR_MAX)? 2:                            1;};template<int64_t v1, int64_t v2>struct get_type{    static const int64_t min = (v1>v2)? v2: v1;    static const int64_t max = (v1>v2)? v1: v2;    typedef typename Typaminia<Typorium<min,max>::typeId>::typeName    type;};template<int64_t v>struct get_type<v, v>{    typedef typename Typaminia<Typorium<v,v>::typeId>::typeName    type;};

بالمناسبة .. الكود ليس بحاجة إلى حالة v==v

 

كيف كان حلّك :) أنا متشوق لمعرفة إن كان في نفس السطر بداخل نفس القالب :D

 

بارك الله فيك ...

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0
يبدو أنه يحتاج لتأكيد بأن المحتوى هو نوع :)

عندما تكون داخل template class و تريد الإشارة إلى نوع داخل template class اخرى لابد ان تستخدم typename حتى يعلم المترجم ان الذى تشير إليه هو نوع.

 

بالمناسبة .. الكود ليس بحاجة إلى حالة v==v

و اين هى v==v؟

 

و إليك حلي:

template<bool cond, typename tt, typename ft> struct If { typedef tt type; };template<typename tt, typename ft> struct If<false, tt, ft> { typedef ft type; };template<int64_t min, int64_t max>struct get{	typedef typename	If< SCHAR_MIN <= min && SCHAR_MAX >= max, int8_t, typename 		If< SHRT_MIN <= min  && SHRT_MAX >= max, int16_t, typename			If< INT_MIN <= min && INT_MAX >= max, int32_t, int64_t			>::type		>::type	>::type type;};template<int64_t v1, int64_t v2>struct get_type{	static const int64_t min = (v1>v2)? v2: v1;	static const int64_t max = (v1>v2)? v1: v2;	typedef typename get<min, max>::type type;};template<int64_t v>struct get_type<v, v>{	typedef typename get<v, v>::type type;};

توجد بعض الإختلافات بين طريقتي و طريقتك و لكن كلاهما صحيح.

 

الإسلوب الذى قمت انت بإتباعه يسهل قرائته و تصحيحه و يصعب تطويره مع الوقت لأن كل نوع لديك لابد و ان يكون له رقم و بالتالي ستحتاج لمعالجة نوعين من الاكواد بدلا من واحد.

الإسلوب الذى اتبعته انا إن لم تكن معتاد على كود الـ templates سيكون من الصعب قرائته و لكنه يسهل تصحيحه و تطويره لإستخدام اسماء الأنواع مباشرة و لأنى استخدمت indent لشكل الكود.

 

إذا اردت المتابعة فى الأمثله اخبرني.

 

 

و الله ولي التوفيق

1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

عجباً ...:D ظننت أن IF من الــstandard  ولكن الحمد لله رأيت القالب الحاص بها قبل أن [email protected]#$^ ...

نعم بالطبع أريد المزيد من الأمثلة إن لم يكن هذا يزعجك ..

 


و اين هى v==v؟

هنا :

template<int64_t v1, int64_t v2>struct get_type{    static const int64_t min = (v1>v2)? v2: v1;    static const int64_t max = (v1>v2)? v1: v2;    typedef typename get<min, max>::type type;};template<int64_t v>struct get_type<v, v>{    typedef typename get<v, v>::type type;};

لا داعي للقالب v1==v2 .. أقصد هذا :

template<int64_t v>struct get_type<v, v>

الإسلوب الذى اتبعته انا إن لم تكن معتاد على كود الـ templates سيكون من الصعب قرائته و لكنه يسهل تصحيحه و تطويره

نعم هو كذلك .. قالب الـ IF  رائع .. والكود قابل للتطوير بسهولة .. ولكن فهمه لم يكن صعباً فلي تجربة مع لغة BrainF**k جعلت كل ما أدرسه بعدها هيّناً ... أنصحك بالاطلاع عليها .. ستعطيك مرونة عقليّة هائلة .. وأسلوب indent فيها (يسمّونه [.. Branch in Branch [in Branch هو الوسيلة الوحيدة لعمل switch هكذا يكون شكله :

--[--[----[--[----[--[[-](code)](code)](code)](code)](code)](code)]

حيث (code) خاص بـ case معيّنة .. .. ما علينا . :D

بالمناسبة .. إذا استعملت #define مع templates يمكنك إنتاج أكواد ذات قدرات تطويرية عالية .. يعني كلما رأيت اسطر مكررة لا يمكن تجنّبها .. اعمل لها MACRO .. أراك لا تحب استخدامه على نصيحة Stroustrup :)

 

عندي سؤال .. هل الأمور التالية "وفقط"هي التي يعالجها المصرّف وقت الترجمة :

1-const

2-enum

3-typedef والتحقق من الأنواع ..

4-طبعاً template

أقصد بسؤالي أنها كافية لعمل أي MetaProgram ...  فهل هناك غيرها ؟

 

وشكرا جزيلاً للوقت والجهد .. :)

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

لا داعي للقالب v1==v2 .. أقصد هذا :

على العكس، لابد منه إذا اردت تمرير رقم واحد فقط لـ get_type بدلا من رقمين.

 

أنصحك بالاطلاع عليها

أطلعت عليها من قبل، خفيفة و مسلية.

 

بالمناسبة .. إذا استعملت #define مع templates يمكنك إنتاج أكواد ذات قدرات تطويرية عالية .. يعني كلما رأيت اسطر مكررة لا يمكن تجنّبها .. اعمل لها MACRO .. أراك لا تحب استخدامه على نصيحة Stroustrup :)

الكود التالي جزء من مشروع arbitrary precision arithmetic الذى اعمل عليه:

#define MATHX_DEFINE_NC(tn, base_type) \template<> \struct numeric_cast<tn> \		: public imp::value_t<tn>, \		  public mxi::base_type<tn> \{ \	typedef imp::value_t<tn> vt; \	typedef mxi::base_type<tn> base; \\	inline numeric_cast<tn>(const tn& input) : vt(input), base( dynamic_cast<vt&>(*this) ) {} \};// from char to int_t/uint_tMATHX_DEFINE_NC(char, int_to_inum)// from signed char to int_t/uint_tMATHX_DEFINE_NC(signed char, int_to_inum)// from unsigned char to int_t/uint_tMATHX_DEFINE_NC(unsigned char, int_to_inum)// from wchar_t to int_t/uint_tMATHX_DEFINE_NC(wchar_t, int_to_inum)// from signed short int to int_t/uint_tMATHX_DEFINE_NC(signed short int, int_to_inum)// from signed int to int_t/uint_tMATHX_DEFINE_NC(signed int, int_to_inum)// from signed long int to int_t/uint_tMATHX_DEFINE_NC(signed long int, int_to_inum)// from signed long long int to int_t/uint_tMATHX_DEFINE_NC(signed long long int, int_to_inum)// from unsigned short int to int_t/uint_tMATHX_DEFINE_NC(unsigned short int, int_to_inum)// from unsigned int to int_t/uint_tMATHX_DEFINE_NC(unsigned int, int_to_inum)// from unsigned long int to int_t/uint_tMATHX_DEFINE_NC(unsigned long int, int_to_inum)// from unsigned long long int to int_t/uint_tMATHX_DEFINE_NC(unsigned long long int, int_to_inum)

كما ترى استخدام الماكرو جعل الكود واضح و مفهوم، و عدم استخدام الماكرو سيجعل الكود اكبر و صعب التصحيح و المراجعه. هناك بعض الحالات التى لا غني عن استخدام الـ Preprocessor.

 

عندي سؤال .. هل الأمور التالية "وفقط"هي التي يعالجها المصرّف وقت الترجمة :

أقصد بسؤالي أنها كافية لعمل أي MetaProgram ... فهل هناك غيرها ؟

إذا كنت تقصد لجعل المترجم اعطائك قيمة literal او typename وقت الترجمه ففي هذه الحالة تحتاج لإستخدام enum او static const مع أنواع الأرقام الصحيحة و typedef للانواع، أيضا بعض المترجمات تسمح لك بإستخدام float-point literal داخل الـ expressions التى تحسب قيم معينة. الأمثلة التى نطبقها حتى الأن من هذا النوع.

لاحظ ان مفهوم عمل meta-program كبير جدا فيمكنني مثلا ان اقوم بعمل برنامج بهدف معين و لكن معالمه غير محدوده، فمثلا انا اعمل على مكتبة لإدارة الذاكرة بشكل فعال، و احد المشاكل التى واجهتنى هى انى اريد جعل المستخدم ان يكتب memory algorithm من عنده و يجيب بداخلها على اسئلة مثل هل يستطيع عمل defrag؟ هل يستطيع التعامل مع ذاكرة ثايته ... و غيرها من الأسئلة و التى بناءا على إجابتها ساقوم يإستخدام انواع من شانها استدعاء دوال قام بتعريفها او لم يقم بتعريفها، مثال بالكود:

template<bool whatever, ...> struct memory_config {};template<typename config> struct memory_provider {};template<typename config> struct memory_tracker{	void notify_defrag(...);	void notify_resize(...);	...};template<typename config> struct null_tracker : memory_tracker<config>{	void notify_defrag(...) {}	void notify_resize(...) {}};template<typename config> struct defrag_tracker : memory_tracker<config>{	void notify_defrag(...) { defrag(...); }	void notify_resize(...) {}};template<typename config> struct resize_tracker : memory_tracker<config>{	void notify_defrag(...) {}	void notify_resize(...) { resize(...); }};template<typename config> struct full_tracker : memory_tracker<config>{	void notify_defrag(...) { defrag(...); }	void notify_resize(...) { resize(...); }};template<typename config>struct memory_algorithm{	static const bool can_resize = true;	static const bool can_defrag = true;	void defrag(...) {}	void resize(...) {}};template<typename config, typename provider, template<typename> class algorithm,		 typename tracker =			typename IF< !algorithm<config>::can_resize && !algorithm<config>::can_defrag, full_tracker<config>,				typename IF< !algorithm<config>::can_resize && algorithm<config>::can_defrag, defrag_tracker<config>,					typename IF< algorithm<config>::can_resize && !algorithm<config>::can_defrag, resize_tracker<config>,						typename IF< algorithm<config>::can_resize && algorithm<config>::can_defrag, full_tracker<config>						>::type					>::type				>::type			>::type		>struct memory_manager : public tracker, public algorithm<config>{	...	...	...};

الكود بالمثال هو تصميم اولي قديم تم حذف منه العديد من الاكواد لتقريب فكره محدودة.

ما يهمنا هو تصميم الفئة memory_manager و بالاخص تعريف الـ tracker و الذى منه سيتم عملية إستدعاء دوال تحجيم و ترتيب الذاكرة فإن قمت بتمرير tracker من لديك فالمشكلة محلولة اما إن لم تقم فسيقوم البرنامج بإختيار واحدة يتناسب مع تصميم الـ algorithm التى كتيتها.

 

كما ترى اى فئة تقبل معامل واحد و تحتوى على الثابتين بالإسماء المحددة يمكن استخدمها كـ base class و بالطبع إن كانت قيم الثابتين بـ false حينها لا داعي ان تقوم بتعريف الدوال resize و defrag حيث ان الـ null tracker لن يستدعيهم و بالتالي لن يستخدموا و بالتالي حتى و إن كانوا موجودين فسيقوم المترجم بحذف الكود الخاص بهم لعدم الحاجة إليه.

 

لى عودة بسؤال جديد.

 

 

و الله ولي التوفيق

تم تعديل بواسطه C++er
1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

انواع بيانات الأرقام الصحيحة يمكنها ترميز عدد محدود من القيم، المطلوب هو تصميم فئة تستقبل نوع البيانات و الأساس و يتم إعطائك عدد القيم التى يمكن ترميزها لذلك الأساس داخل النوع المحدد.

 

لاحظ أن الأساس المدخل ايا كان قيمته لابد دائما ان يكون فى مدى من 2 و حتى أكبر قيمة يمكن ترميزها داخل النوع المدخل بإضافة واحد، مثلا النوع unsigned char يمكنه تمثيل الأرقام فى المدى من [0, 255] و بالتالي مدى الأساس المسموح به هو [2, 256]، إذا تم إدخال قيمة اكبر من 256 او اقل من 2 تفشل ترجمة البرنامج و السبب لا يهم، المهم هو عدم ترجمة البرنامج.

 

مدى قيمة الأساس للنوع unsigned long long هى اكبر قيمة يمكن تمثيلها به و السبب واضح و هو ان اضافة واحد سيسبب overflow.

 

الفئة التى ستقوم بتصميمها لابد وان تعطيك النتيجة على شكل رقم واحد يمثل عدد الخانات التى يمكن تمثيلها للأساس داخل النوع المحدد، و لابد ان يكون كيفية التعامل معها كالتالي:

digits_in_base_for_type<unsigned int, 3>::value

حيث digits_in_base_for_type هو اسم الفئة، unsigned int هو النوع المدخل، 3 هو قيمة الأساس، value هو ثابت يعود بالقيمة المطلوبة.

 

لاحظ ايضا انه يمكن استدعاء هذه الفئة بدون الأساس و فى هذه الحالة يفترض ان يكون 10.

 

مستوى هذا المثال فوق المتوسط.

 

الـ test case ساقوم بإضافتها بعد قليل.

 

 

و الله ولي التوفيق

تم تعديل بواسطه C++er
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

سبقتك :D

#include <iostream>#include <climits>using std::cout;using std::endl;typedef unsigned long long int ulli;template <typename x>struct getMax{static const ulli max = 0;};template <>struct getMax<unsigned char            >{static const ulli max = UCHAR_MAX    ;};template <>struct getMax<unsigned short int        >{static const ulli max = USHRT_MAX    ;};template <>struct getMax<unsigned int            >{static const ulli max = UINT_MAX    ;};template <>struct getMax<unsigned long long int    >{static const ulli max = ULLONG_MAX;};template<typename tName,ulli base  ,ulli tmp >struct digits_in_base_for_type_counter{    static const ulli value = tmp/base?1+digits_in_base_for_type_counter<tName,base,tmp/base>::value:0;};template<typename tName,ulli base>struct digits_in_base_for_type_counter<tName,base,0>{    static const ulli value = 0;};template <bool condition,ulli ifTrue>struct If{    static const ulli _=ifTrue;};template <ulli ifTrue>struct If<false,ifTrue>{static const ulli _=Hello World!;};template <    typename tName    ,    ulli base = 10 >struct digits_in_base_for_type{    static const ulli value = If<    base<getMax<tName>::max,        digits_in_base_for_type_counter < tName , base , getMax<tName>::max    >::value    >::_;        };int main(){    //cout << digits_in_base_for_type<unsigned char    , 9999>::value << endl ;//not compiled    cout << digits_in_base_for_type<unsigned short    , 2>::value << endl ;    cout << digits_in_base_for_type<unsigned int    , 2>::value << endl ;    cout << digits_in_base_for_type<unsigned long long int, 2>::value << endl ;    return 0;}

ما رأيك :)

إذا كان عندك أفكار أخرى .. أخبرني بها قبل أن تضع الحل .. وإذا كان هناك شروط أكثر تخصيصاً للحل للوصول لفكرة معيّنة .. أيضاً أخبرني بها قبل أن تضع حلّك :)

جزاك الله خيراً :)

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

اولا: الكود لم يترجم.

ثانيا: الكود لا يعمل مع الـ signed types.

ثالثا: أكبر قيمة للنوع بالإضافة لواحد لا تقبل داخل الأساس.

رابعا: التنسيق سيئ يجعل قرائة الكود صعبة.

 

تم تجربة الكود و لم يعمل على التالي:

g++ 4.8.1

vc++ 2008 sp1

clang 3.3

intel c++ XE 14.0

 

 

و الله ولي التوفيق

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

:D

4- سأحسّن التنسيق  .. ( قصدك هذه  _ :D )

3- حلها بسيط إن شاء الله

2- سأضيف بعض الأسطر .. أو سأغير الكود بالكامل لهذه النقطة .. (حاليا سأضيف بعض الأسطر )

1- اشتغل عندي على VC++8 Express Edition !!! ولكن لم يعمل على g++ ولا على VC6 (الأخير لم يسمح بالإسناد داخل struct من أصلها )

 

لا بأس ... الفشل أفضل من النجاح

شكراً لك :)

1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

انس كل كلمة كتبتها من أول الموضوع ... أنا لم أعد أفهم شيئاً !!

أبسط ما كنت متيقّناً منه لم يعد يعمل !

template <class T>void foo(){    What On Earth ?}int main(){    return 0;}

طول عمره الكود السابق كان يشتغل معي على VC6 لماذا لا يعمل على 8 ولا على g++

أليس المفترض ألا يتم توليد الكود لأنه لم يتم استدعاء الدالة أبداً ..

سأبحث على .. النت وجدت رابط يناسبني An-Idiots-Guide-to-Cplusplus-Templates ..لكل من يقرأ : عرفت ليه الفشل أفضل من النجاح :)؟

تم تعديل بواسطه مصطفى 36a2
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

المشكلة لديك فى تعريف If عندما يكون الشرط خاطئ حيث الكلمة hello world!، جرب هذه النسخة:

#include <iostream>#include <climits>using std::cout;using std::endl;typedef unsigned long long int ulli;template <typename x>struct getMax{static const ulli max = 0;};template <>struct getMax<unsigned char            >{static const ulli max = UCHAR_MAX    ;};template <>struct getMax<unsigned short int        >{static const ulli max = USHRT_MAX    ;};template <>struct getMax<unsigned int            >{static const ulli max = UINT_MAX    ;};template <>struct getMax<unsigned long long int    >{static const ulli max = ULLONG_MAX;};template<typename tName, ulli base, ulli tmp>struct digits_in_base_for_type_counter{    static const ulli value = tmp / base? (1 + digits_in_base_for_type_counter<tName, base, tmp/base>::value): 0;};template<typename tName,ulli base>struct digits_in_base_for_type_counter<tName, base, 0>{    static const ulli value = 0;};template <bool condition,ulli ifTrue> struct If{ static const ulli _ = ifTrue; };template <ulli ifTrue> struct If<false, ifTrue>;template <typename tName, ulli base = 10>struct digits_in_base_for_type{    static const ulli value = If< base < getMax<tName>::max,								  digits_in_base_for_type_counter<tName, base, getMax<tName>::max>::value								>::_;};int main(){    cout << digits_in_base_for_type<unsigned char    , 9999>::value << endl ;//not compiled    cout << digits_in_base_for_type<unsigned short    , 2>::value << endl ;    cout << digits_in_base_for_type<unsigned int    , 2>::value << endl ;    cout << digits_in_base_for_type<unsigned long long int, 2>::value << endl ;    return 0;}

كل ما فعلته هو حذف تعريف If و بالتالي سيحدث خطأ عند محاولة إستخدامها.

 

قمت بتوليد test case للتحقق من صحة digits_in_base_for_type قم بتحميله من المرفقات، أضف الـ headers التى تحتاجها ثم اضف الكود الخاص بك مكان الـ multiline comment و جربه.

 

المفترض ان تنجح عملية الترجمه إذا كان الكود الخاص بك ملتزم بقواعد السؤال فإن فشلت فستحتاج لمراجعة الكود الخاص بك مع معطيات السؤال.

إن نجحت الترجمه إما يطبع لك all test passed و هذا يعنى ان الكود الخاص بك سليم او ان يطبع لك رسالة خطأ بمكان الـ case التى فشل عندها الإختبار كالتالي:

case 100 failed.

و هذا يعنى ان تقوم بعد 100 حالة ببدء العد من 1.

 

 

أليس المفترض ألا يتم توليد الكود لأنه لم يتم استدعاء الدالة أبداً ..

كود الـ template لا يتبع lazy evaluation، و هذا يعنى سيتم التحقق من كل الحالات و سيتم العودة بالحالة المثلي.

 

 

و الله ولي التوفيق

test.cpp

تم تعديل بواسطه C++er
1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

بالنسبة للـIF فقد تعمدت وضعها حتى يظهر Compile error عندما لا يتحقق الشرط

على كل حال هذا هو الكود المطلوب ولكنه لا يحقق المجال المطلوب .. (وحصلت على all test passed)

#include <iostream>#include <climits>using std::cout;using std::endl;typedef unsigned long long int ulli;template <typename x>struct getMax{static const ulli max = 0;};template <>struct getMax<unsigned char            >{static const ulli max = UCHAR_MAX    ;};template <>struct getMax<signed char            >{static const ulli max = CHAR_MAX    ;};template <>struct getMax<unsigned short int        >{static const ulli max = USHRT_MAX    ;};template <>struct getMax<signed short int        >{static const ulli max = SHRT_MAX    ;};template <>struct getMax<unsigned int            >{static const ulli max = UINT_MAX    ;};template <>struct getMax<signed int            >{static const ulli max = INT_MAX    ;};template <>struct getMax<unsigned long long int    >{static const ulli max = ULLONG_MAX;};template <>struct getMax<signed long long int    >{static const ulli max = LLONG_MAX;};template<ulli base  ,ulli num >    struct counter    {        static const ulli value = (counter<base,num/base>::value)+bool(num);    };template<ulli base>    struct counter<base,0>    {        static const ulli value = 0;    };template <    typename tName    ,    ulli base = 10 >    struct digits_in_base_for_type    {        static const ulli value =            (base<2||((base-1)<=getMax<tName>::max))?counter < base , getMax<tName>::max    >::value    : 0;    };

فكيف أمنع المستخدم من إضافة القيم الممنوعة ؟

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

من فضلك سجل دخول لتتمكن من التعليق

ستتمكن من اضافه تعليقات بعد التسجيل



سجل دخولك الان

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .