أساسيات قالب C ++: قوالب الوظائف

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



من المستحيل فهم لغة C ++ الحديثة دون معرفة أنماط البرمجة. تفتح خاصية اللغة هذه إمكانيات واسعة لتحسين الشفرة وإعادة استخدامها. في هذه المقالة ، سنحاول معرفة ما هو وكيف يعمل كل شيء.

تسمح لنا آلية القوالب في C ++ بحل مشكلة توحيد الخوارزمية لأنواع مختلفة: ليست هناك حاجة لكتابة وظائف مختلفة لأنواع عدد صحيح أو حقيقي أو مستخدم - يكفي تجميع خوارزمية معممة لا تعتمد على نوع البيانات ، بناءً على الخصائص الشائعة فقط. على سبيل المثال ، يمكن أن تعمل خوارزمية الفرز مع الأعداد الصحيحة وكذلك مع الكائنات من النوع "السيارة".

هناك قوالب وظيفة وقوالب الفئة.

قوالب الوظائف هي وصف عام لسلوك الوظائف التي يمكن استدعاؤها لكائنات من أنواع مختلفة. بمعنى آخر ، قالب الوظيفة (دالة القالب ، الدالة المعممة) عبارة عن مجموعة من الوظائف المختلفة (أو وصف خوارزمية). حسب الوصف ، يشبه قالب الوظيفة وظيفة عادية: الفرق هو أن بعض العناصر غير محددة (أنواع ، ثوابت) ويتم تحديدها.

قوالب الفئات - وصف عام لنوع المستخدم يمكن فيه تحديد سمات العمليات ونوعها. إنها إنشاءات يمكن من خلالها إنشاء فئات حقيقية عن طريق استبدال الوسائط الفعلية بدلاً من المعلمات.

لننظر في قوالب الوظائف بمزيد من التفاصيل.

قوالب وظيفة


كيف تكتب أول قالب وظيفة؟


النظر في حالة تحديد الحد الأدنى للعنصر اثنين. في حالة الأعداد الصحيحة والأعداد الحقيقية ، سيكون عليك كتابة وظيفتين.

int _min(int a, int b){ if( a < b){ return a; } return b; } double _min(double a, double b){ if( a < b){ return a; } return b; } 

يمكنك بالطبع تنفيذ وظيفة واحدة فقط ، مع معلمات صالحة ، ولكن لفهم الأنماط سيكون ذلك ضارًا.
ماذا يحدث إذا تم تجميع التطبيق؟ ستندرج كل من تطبيقات الوظيفة في الكود الثنائي للتطبيق ، حتى لو لم يتم استخدامها (ومع ذلك ، فإن المترجمين أذكياء للغاية الآن ، يمكنهم قطع الكود غير المستخدم). وإذا كنت بحاجة إلى إضافة دالة تحدد الحد الأدنى من سطرين (من الصعب تخيله دون تحديد أن هناك حدًا أدنى للسطر)؟!

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

  1. يتم تنفيذ تنفيذ وظيفة لنوع ما ؛
  2. يتم تعيين قالب الرأس <class type> (أو القالب <typename Type>) ، مما يعني أن الخوارزمية تستخدم نوعًا من أنواع الملخص ؛
  3. في تنفيذ الوظيفة ، يتم استبدال اسم النوع بالنوع.

للحصول على الدالة min ، نحصل على ما يلي:

 template<class Type> Type _min(Type a, Type b){ if( a < b){ return a; } return b; } 

الأكثر إثارة للاهتمام هو حقيقة أنه على الرغم من عدم وجود استدعاء لوظيفة min ، عند التحويل البرمجي ، فإنه لا يتم إنشاؤه في الكود الثنائي (غير متماثل ). وإذا قمت بتعريف مجموعة من استدعاءات الوظائف ذات المتغيرات بأنواعها المختلفة ، فكل مترجم سينشئ تطبيقه الخاص بناءً على القالب.

استدعاء دالة قالب عموماً يعادل استدعاء دالة عادية. في هذه الحالة ، سيحدد المترجم النوع الذي تريد استخدامه بدلاً من النوع ، استنادًا إلى نوع المعلمات الفعلية. ولكن إذا تبين أن المعلمات المستبدلة من أنواع مختلفة ، فلن يتمكن المترجم من إخراج (إنشاء مثيل للقالب) من تنفيذ القالب. لذلك ، في التعليمة البرمجية التالية ، سوف يتعثر المحول البرمجي على المكالمة الثالثة ، لأنه لا يمكن تحديد ما هو نوع (فكر لماذا؟):

 #include <iostream> template<class Type> Type _min(Type a, Type b) { if (a < b) { return a; } return b; } int main(int argc, char** argv) { std::cout << _min(1, 2) << std::endl; std::cout << _min(3.1, 1.2) << std::endl; std::cout << _min(5, 2.1) << std::endl; // oops! return 0; } 

يتم حل هذه المشكلة عن طريق تحديد نوع معين عند استدعاء الوظيفة.

 #include <iostream> template<class Type> Type _min(Type a, Type b) { if (a < b) { return a; } return b; } int main(int argc, char** argv) { std::cout << _min<double>(5, 2.1) << std::endl; return 0; } 

متى ستعمل وظيفة القالب (لا)؟


من حيث المبدأ ، يمكنك فهم أن المترجم يستبدل ببساطة النوع المطلوب في القالب. ولكن هل ستكون الوظيفة الناتجة وظيفية دائمًا؟ من الواضح لا. يمكن تعريف أي خوارزمية بغض النظر عن نوع البيانات ، ولكنها تستخدم بالضرورة خصائص هذه البيانات. في حالة دالة القالب _min ، يعد هذا مطلبًا لتعريف عامل التشغيل (المشغل <).

أي قالب وظيفة يفترض وجود خصائص معينة من نوع معلمات ، وهذا يتوقف على التنفيذ (على سبيل المثال ، مشغل نسخة ، مشغل المقارنة ، وجود طريقة معينة ، وما إلى ذلك). في معيار لغة C ++ المتوقع ، ستكون المفاهيم مسؤولة عن هذا.

وظيفة قالب الزائد


قوالب وظيفة ويمكن أيضا أن تكون مثقلة. عادة ما يتم تنفيذ هذا الزائد عندما

 template<class Type> Type* _min(Type* a, Type* b){ if(*a < *b){ return a; } return b; } 

حالات خاصة


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

 template<> std::string _min(std::string a, std::string b){ if(a.size() < b.size()){ return a; } return b; } 

يتم تخصيص القالب لأنواع محددة مرة أخرى لأسباب الاقتصاد: إذا لم يتم استخدام هذا الإصدار من قالب الوظيفة في الكود ، فلن يتم إدراجه في الكود الثنائي.
بالنسبة للمستقبل ، تبقى معلمات متعددة و عدد صحيح. الامتداد الطبيعي هو قوالب الفصل ، وأساسيات البرمجة التوليفية ، وتصميم مكتبة C ++ القياسية. ومجموعة من الأمثلة!

Source: https://habr.com/ru/post/ar436880/


All Articles