الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

Meta Programming - يا أيها الزمن القديم عد من جديد!

مغلق
بدأه Khaled.Alshaya في 28 مارس 2008 · 10 رد · 3,313 مشاهدة · في قسم المواضيع الهامة في قسم السي /سي++
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم و رحمة الله,

منذ مدة طويلة أسمع عن مصطلح يسمى الـ Meta Programming!

حقيقة لم أكن أفهم ماذا يعني أو على ماذا يدل! حتى وفقني الله لقراءة بعض المقالات الجيدة حول الموضوع و استطعت استيعاب الهدف من وراءه!

الـ Meta Programming هي عملية كتابة كود يقوم بإنشاء كود آخر قبل ترجمة البرنامج باللغة التي تستخدمها! بكل بساطة هي عبارة عن Code Generators.

الكثيرون يعرفون الـ Wizards التي تأتي مع معظم بيئات التطوير الكبيرة, و لكنهم لايعرفون أن هذه الـ Wizards هي بوابة عالم المحترفين, بل الخبراء بمعنى أصح!

لايوجد مبرمج ++C/C على وجه الأرض لايعرف الـ Preprocessors التي تدعمها لغة ++C/C, و هي في الحقيقة من أكثر الأمور التي تشوش على المبرمجين!

فقليل هم الذين يعرفونها حق المعرفة, و ذلك ليس عيباً! فهي لغة أخرى ليس لها دخل أصلاً بلغة ++C أو C على الإطلاق.

عندما تقوم بكتابة كود ما بلغتك المفضلة C أو ++C, فلن يقوم المترجم الذي تستخدمه بترجمة الكود الذي قمت بكتابته مباشرة!

سيمر الكود قبل ذلك على مرحلة مهمة جداً و هي عملية الـ Preprocessing,

لاحظ عندما تقوم بكتابة أي كود بلغة C أو ++C أنك ستقوم بكتابة أسطر من الكود مسبوقة بالعلامة #, و كمثال على ذلك عملية تضمين ملف آخر على الشكل التالي :

#include <iostream>

هل تعتقد أن السطر السابق سيفهمه مترجم لغة ++C/C, في الحقيقة أن المترجم لا يعرف عنه أي شيء!

السطر السابق هو من اختصاص الـPreprocessor, و الذي بدوره لا يعرف أي شيء عن لغة ++C/C :D

جميع الأسطر المسبوقة بالعلامة #, يتم معالجتها, إما يتم استبدالها بكود أو تطبيق شيء على الكود الحالي و هكذا! و لكن تذكر أن الـ Preprocessor لا يعرف أي شيء عن لغة ++C/C أو قواعدها على الإطلاق,

لهذا ستجد أنه من الصعوبة بمكان اكتشاف أخطاء الـ Preprocessor Directives في كثير من الأحيان!

من هنا نرى أن القوة الكامنة في لغة ++C/C ليست في اللغة لوحدها و إنما في مجموعة الأدوات المتوفرة لمبرمجين هاتين اللغتين, و التي يسمع عنها المبرمجون الآخرون و لكنهم لم و لن يصلوا لتفكير مبرمجي ++C/C مهما طال الزمان :P (على سبيل المزاح لا أكثر :) )

تعتبر الـ preprocessor من أبسط لغات الـ Meta Programming في العالم

على العموم إن كنت تعتقد أن هذا أقصى ما توفره لغة C, فتوقف قليلاً و انظر حولك, مالذي أثار عطش المبرمجين الكبار حول العالم! إنها القوالب أو الـ Templates في ++C,

لن أتكلم عن الـ Templates في ++C, لأني لن أوفيها حقها فمعرفتي البرمجية لم تلامس إلا أسطح ذلك العلم,

و لكن دعني أقول لك أنه عن طريق الـ Templates يمكنك صناعة لغة برمجة جديدة, صدق أو لا تصدق ؟!

فالقوالب هي لغة مختلفة تماماً عن لغة ++C, على الرغم من أن القوالب ينتج عنها كود ++C يقوم المترجم بترجمته بشكل طبيعي!

إذا وصلت لنهاية هذا الموضوع فأرجو منك أن تعطينا من وقتك قليلاً و تخبرنا ماهو الشيء الذي لم تفهمه في عمل الـ preprocessors في لغة الـ C أو ماهو الشيء الذي أثار انتباهك في القوالب في لغة ++C,

شارك بخبرتك حول الموضوع فربما تفيد الآخرين بشيء لم يعرفوه من قبل!

و السلام عليكم و رحمة الله و بركاته.

#2

السلام عليكم

---------

اقتباس
و لكن دعني أقول لك أنه عن طريق الـ Templates يمكنك صناعة لغة برمجة جديدة, صدق أو لا تصدق ؟!

فالقوالب هي لغة مختلفة تماماً عن لغة ++C, على الرغم من أن القوالب ينتج عنها كود ++C يقوم المترجم بترجمته بشكل طبيعي!

هناك مصداقية لكلامك السابق هذا بواسطة العالِم Bjaren Stroustrup..اول مرة عمل لغة C++ قال بأنه يرى في هذه اللغة لغات زغيرة رايحة تطلع للوجود..وبالفعل طلعت لغات واشتقت لغات من لغة ++C تحديداً. بالطبع انا مكنت عارفة شو بيقصد إلا الآن استاذنا بخصوص القوالب Tamplate.. :happy:

======

اقتباس
الـ Meta Programming هي عملية كتابة كود يقوم بإنشاء كود آخر قبل ترجمة البرنامج باللغة التي تستخدمها! بكل بساطة هي عبارة عن Code Generators.

بالمناسبة وبخصوص Meta Programming..شو رايك بأن هناك تقنية كاملة بمكتبة Qt للميتا هذي..وبالفعل مثل ما تفضلت اخي خالد..بخصوص Qt اسم التقنية Meta Object وهذي لزما تكون مكتوبة كأمر ببداية إنشاء الصنف كالتالي

QOBJECT

تقريباً علشان تقوم تقنية Qt من إنشاء الصنف ضمن المواصفات الخاصة بها (الوراثة تحديداً من مكتبتها)..

=======

آسفة بيخوني التعبير بعض الأحيان :happy:

=========

وموضوع اكتر من ممتاز

=========

أطيب المُنى

[وسط]

♥ Countess ♥

57899411.gif

♥

[/وسط]

#3

السلام عليكم,

موضوع جميل أخى خالد و شيق جدا, بالنسبة لى على الأقل. أنا لم أدرك ما يمكننى عمله بال preprocessor إلا من وقت قريب جدا! كنت بكتب كود بس علشان أعمله debugging كان لازم أضيف عليه أسطر كتيرة أو أنادى دوال تانية خالص غير اللى أنا بستخدمها فى ال normal operation بتاعة البرنامج, ففكرت فى إستخدام ال preprocessor للقيام بهذه المهام و فعلا بعد ما كتبتها ذهلت بالقوة اللى ممكن أضيفها على الكود بتاعى عن طريق ال conditional compiling اللى بيوفرها ال preprocessor! بقى الموضوع سهل لدرجة إنى لو عايز أعمل كومبايل لل debug أقوم معرف ثابت DEBUG مثلا فى أول الكود و أعمل build و خلاص!

#4

السلام عليكم

هل ممكن أن تعطونا مثال عملي بسيط

لأني حاسس إني مشوش

#5

Preprocessor:

#include <iostream>

using std::cout;
using std::endl;

int main()
{
   cout << "__LINE__ = " << __LINE__ << endl
		<< "__FILE__ = " << __FILE__ << endl
		<< "__DATE__ = " << __DATE__ << endl
		<< "__TIME__ = " << __TIME__ << endl;

   return 0;

}

Templates:

#include <iostream>

using std::cout;
using std::endl;

template< class T >
void printArray( const T *array, const int count )
{
   for ( int i = 0; i < count; i++ )
	  cout << array[ i ] << " ";

   cout << endl;

}

int main()
{
   const int aCount = 5, bCount = 7, cCount = 6;

   int a[ aCount ] = { 1, 2, 3, 4, 5 };
   double b[ bCount ] = { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7 };
   char c[ cCount ] = "HELLO";  
   cout << "Array a contains:" << endl;

   printArray( a, aCount );  

   cout << "Array b contains:" << endl;

   printArray( b, bCount );  

   cout << "Array c contains:" << endl;

   printArray( c, cCount );  

   return 0;

}

Chao!!!

Great place, and people, but full of sectarianism.

#6

لا يمكن ان لا نذكر inline فهي نوع من Meta Programming لما تقوم به

( _ /)

(='.'=)

(")-(")

#7
"garo" كتب:
لا يمكن ان لا نذكر inline فهي نوع من Meta Programming لما تقوم ب

لماذا تعتبر ال inline نوع من ال meta-programming يا أخى يا ريت توضح؟

#8
اقتباس
أهلاً بالأخوة و الأخوات,

شكراً أخت رغد على الإضافة الرائعة, و أنا كنت من متابعي موضوع Qt :wink:

وضوع جميل أخى خالد و شيق جدا, بالنسبة لى على الأقل. أنا لم أدرك ما يمكننى عمله بال preprocessor إلا من وقت قريب جدا! كنت بكتب كود بس علشان أعمله debugging كان لازم أضيف عليه أسطر كتيرة أو أنادى دوال تانية خالص غير اللى أنا بستخدمها فى ال normal operation بتاعة البرنامج, ففكرت فى إستخدام ال preprocessor للقيام بهذه المهام و فعلا بعد ما كتبتها ذهلت بالقوة اللى ممكن أضيفها على الكود بتاعى عن طريق ال conditional compiling اللى بيوفرها ال preprocessor! بقى الموضوع سهل لدرجة إنى لو عايز أعمل كومبايل لل debug أقوم معرف ثابت DEBUG مثلا فى أول الكود و أعمل build و خلاص!

في الحقيقة أنك سبقتني بطرح مثال رائع على الموضوع :D

ما يسمى بالـ Conditional Compiling هو احدى تطبيقات الـ cpp في لغة ++C/C,

لا يمكن أن أتصور win32 مثلاً بدون الترجمة المشروطة, لا أدري هل كنا سنحتاج لكتابة البرنامج مرتين حتى يعمل على NT و يعمل على ما قبله win98 & win95 :S

عند البرمجة تحت Windows, ستواجهنا مشكلة تحديد ترميز المحارف, فويندوز NT و 2000 و xp و vista تدعم Unicode, بينما جميع الأنظمة التي تسبق هذه الأنظمة تدعم ASCII,

عملية ترجمة برنامج لكلا المنصتين يعني إعادة تعريف أنواع و استخدام دوال خاصة بكل نوع ترميز وووووووو.......

و لكن من خلال الـ Macros التي توفرها مكتبة windows لن تكلفك عملية نقل برنامج مصمم لـ win98 إلى منصة windows2000 سوى إضافة هذا السطر :

#define UNICODE

تصور :wacko: في الحقيقة دع الـ Macros تختار الدالة المناسبة للترميز المناسب, حاولوا القراءة حول الموضوع, فهو إحدى أهم مفاهيم برمجة النصوص من خلال مكتبة win32,

أعتقد أن هذا ما يجعل مكتبة Windows بلغة C, و هو إمكانية عمل Conditional Compiling دون اللجوء لتعديل الكود الذي نقوم بكتابته عن طريق الـ meta programming !

أخ da666ni, المثال الذي وضعته جميل و لكني سأحاول عرض مثالين يوضحان فائدة الـ Macros في تطبيقات حقيقة و تحديداً في مكتبة win32,

أعرف أن كلامي حول الـ Conditional Compiling لم يكن واضحاً كفاية و لكني سأقوم بشرح المثالين الذين لدي حتى يطلع عليهما من يريد,

سأقوم بتجهيز رد في القريب العاجل و ارساله للمنتدى :)

أخ garo, التعليمة inline هي اقتراح للمترجم مثل التعليمة register و ما شابههما,

هذا النوع من التعليمات يؤثر على الـ Binary Code الناتج, و لغات الـ meta languages لا تدخل هذا المضمار,

قد يكون هناك تشابه بين ما تقوم به inline و الـ cpp و لكن هناك فرق,

inline هي اقتراح لترجمة كود الدالة بطريقة معينة, بينما لغات الـ meta هي عبارة عن لغات Text Processing لا أكثر!

تحياتي لمشاركتكم و سأعود لاحقاً لإضافة المثالين الذين تكلمت عنهما في الرد في أقرب فرصة,

تحياتي,,

#9

اهلين اخواني

هذا المثال الي وضعه الاستاذ Zeeshan Amjad

// Name:		NLUMP.h
// Author: 		Zeeshan Amjad
// Description: 	Numbter theory Library Using Meta Programming

#ifndef __NLUMP_H
#define __NLUMP_H

// check divisibility
template <int u, int v>
class Divisible
{
public:
	enum { value = u % v == 0 ? 1 : 0 };
};

// check divide by zero condition
template <int u>
class Divisible<u, 0>
{
public:
	enum { value = -1 };
};

// check if one number is divide by other
template <int u, int v>
class DivisibleDigit
{
public:
	enum { value = u % v == 0 ? v : 0 };
};

// check divide by zero condition
template <int u>
class DivisibleDigit<u, 0>
{
public:
	enum { value = -1 };
};

// check number is even or not
template <int u>
class IsEven
{
public:
	enum { value = Divisible<u, 2>::value };
};

// check number is odd or not
template <int u>
class IsOdd
{
public:
	enum { value = Divisible<u, 2>::value == 0 ? 1 : 0 };
};

// loop for total no of divisors
template <int Start, int End>
class NumDivisorsLoop
{
public:
	enum { value = Divisible<End, Start>::value + 
			NumDivisorsLoop<Start + 1, End>::value };
};

// partial specialization to terminate loop
template <int End>
class NumDivisorsLoop<End, End>
{
public:
	enum { value = 1 };
};

// number of divisor of any digit
template <int n>
class NoOfDivisor
{
public:
	enum { value = NumDivisorsLoop<1, n>::value };
};

// loop for sum of divisor
template <int Start, int End>
class SumOfDivisorLoop
{
public:
	enum { value = DivisibleDigit<End, Start>::value + SumOfDivisorLoop<Start + 1, End>::value };
};

template <int End>
class SumOfDivisorLoop<End, End>
{
public:
	enum { value = DivisibleDigit<End, End>::value };
};

// check no is perfect or not
template <int n>
class IsPerfect
{
public:
	enum { value = SumOfDivisor<n>::value - n == n ? 1 : 0 };
};

// calculate gcd
template <int u, int v>
class gcd
{
public:
	enum { value = gcd<v, u % v>::value };
};

template <int u>
class gcd<u, 0>
{
public:
	enum { value = u };
};

template <>
class gcd<0, 0>
{
public:
	enum { value = -1 };
};

// calculate lcm
template <int u, int v>
class lcm
{
public:
	enum { value = u * v / gcd<u, v>::value };
};

// check if numbers are coprime (relative prime) or not
template <int u, int v>
class CoPrime
{
public:
	enum { value = gcd<u, v>::value == 1 ? 1 : 0 };
};

// to calculate the power
template <int a, int b>
class Power
{
public:
	enum { value = a*Power<a, b-1>::value };
};

template <int a>
class Power<a, 0>
{
public:
	enum { value = 1 };
};

// to calculate Permutations
template <int n, int r>
class Permutations
{
public:
	enum { value = Factorial<n>::value / Factorial<n-r>::value };
};

// to calculate Combination
template <int n, int r>
class Combination
{
public:
	enum { value = Factorial<n>::value / Factorial<r>::value * Factorial<n-r>::value };
};

// helper template loop for calculate totient function
template <int Start, int End>
class TotientLoop
{
public:
	enum { value = CoPrime<Start, End>::value + TotientLoop<Start + 1, End>::value };
};

template <int End>
class TotientLoop<End, End>
{
public:
	enum { value = 0 };
};

// totient function
template <int n>
class Totient
{
public:
	enum { value = TotientLoop<1, n>::value };
};

template <>
class Totient<1>
{
public:
	enum { value = 1 };
};

template <>
class Totient<0>
{
public:
	enum { value = 1 };
};

// loop for divisor function
template <int Start, int End, int x>
class DivisorLoop
{
public:
	enum { value = (Divisible<End, Start>::value == 1 ? Power<Start, x>::value : 0) + 
		DivisorLoop<Start+1, End, x>::value };
};

template <int End, int x>
class DivisorLoop<End, End, x>
{
public:
	enum { value = Power<End, x>::value };
};

// to calculate divisor function
template <int n, int x>
class Divisor
{
public:
	enum { value = DivisorLoop<1, n, x>::value };
};

// check the given number is prime or not
template <int n>
class IsPrime
{
public:
	enum { value = NoOfDivisor<n>::value == 2 ? 1 : 0 };
};

// calculate the number of prime less than given number
// pi function
template <int n>
class PiFunc
{
public:
	enum { value = IsPrime<n>::value + PiFunc<n-1>::value };
};

template <>
class PiFunc<2>
{
public:
	enum { value = 1 };
};

// totient summatory function loop
template <int Start, int End>
class TotientSummatoryLoop
{
public:
	enum { value = Totient<Start>::value + TotientSummatoryLoop<Start + 1, End>::value };
};

template <int End>
class TotientSummatoryLoop<End, End>
{
public:
	enum { value = Totient<End>::value };
};

// totient summatory function
template <int n>
class TotientSummatory
{
public:
	enum { value = TotientSummatoryLoop<1, n>::value };
};

// to calculate the celing value 
template <typename T>
class Ceil
{
public:
	static inline int value (T a)
	{ return (a > 0 ? a + 1 : a ); }
};

// to calculate the floor value
template <typename T>
class Floor
{
public:
	static inline int value (T a)
	{ return (a > 0 ? a : a - 1); }
};

#endif
llback.jpg

اشهد ان لا إله إلا الله وان محمدا ً رسول الله

#10

السلام عليكم

تسلم أخي da666ni على المثال

ولكن __LINE__

هل هو Macro ؟

#11

نعم, هاد macro, يرجع رقم السطر الموجود في الكود بشكل Integer

Chao!!!

Great place, and people, but full of sectarianism.

هذا الموضوع مغلق.

مواضيع مشابهة