1. استنادًا إلى Meyers "الاستدلال الفعال والحديث c ++" - استدلال نوع القالب

مساء الخير عزيزي القارئ!


هذه المقالة هي الأولى في سلسلة من المقالات المجردة التي سأكتبها عندما أقرأ من خلال كتاب سكوت مايرز ، الفعال والحديث c ++. سيكون لكل من هذه المقالات دليل منفصل في مشروع تم إنشاؤه خصيصًا على github.com مع أمثلة على استخدام الميزات والتقنيات الموصوفة.


استدلال نوع القالب


التصميم الناجح هو عندما لا يعرف المستهلك كيف يعمل الجهاز ، ولكن كل شيء يناسبه.


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


يقسم Meyers النوع - "T" ، الذي يتم عرضه والنوع - "ParamType" ، الذي يصفه المبرمج في تعريف المعلمة.


1. عرض المعلمة - الارتباط أو المؤشر


من أجل فهم قاعدة الاشتقاق بسرعة ، سأعكسها في شكل قالب:


نوع الإدخال -> النوع ، المعلمة -> نوع الإخراجنوع المعلمة النهائي ]


مثال على رابط:


template<typename T> //   T void func(T& param) //   - T& int x = 0; //   int func(x); 

عند إخراج نوع T ، يتم تجاهل المرجع (* ، &) لأنه تم تحديده بالفعل عند تحديد الوظيفة ، كما لو كان يعني "تمرر أي شيء هناك ، سنفترض أن هذا ليس رابطًا ، لأن المرجع تمت إضافته بالفعل في مكان الاستهلاك - في وظيفتنا و "


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


مخطط الانسحاب


 //   int —> (T & param) —> int; const int —> (T & param) —> const int; const int & —> (T & param) —> const int //   int —> (const T & param) —> int; const int —> (const T & param) —> int; const int & —> (const T & param) —> int; //   int * —> (T * param) —> int; const int —> (T * param) —> const int; const int * —> (T * param) —> const int; //   int * —> (const T * param) —> int; const int —> (const T * param) —> int; const int * —> (const T * param) —> int; 

2. نوع الحجة - مرجع عالمي


يذكر سكوت أنه سيتم النظر في الروابط العالمية لاحقًا ، لذا فإن قواعد المعلمات التي يقسمها هنا إلى rvalue و lvalue تحتاج فقط إلى تذكرها بقليل من التفكير.


 template<typename T> void func(const T&& param) 

قواعد الاستدلال للقيمة


هذا ، كما يزعم سكوت ، هو الحالة الوحيدة التي يتم فيها إخراج T كمرجع.
في الأمثلة التالية ، نوع المعلمة في وصف الوظيفة هو مرجع lvalue العالمي . يمكن ملاحظة أن T يتم عرضه كارتباط أو ارتباط ثابت ، حسب
من الوسيطة الإدخال ، نوع المعلمة البارزة نفسها هو أيضًا مرجع في هذه الحالة.


 lvalue int —> (T &&param) —> int &, param - int& lvalue const int —> (T &&param) —> const int &, param - const int& lvalue const int & —> (T &&param) —> const int &, param - const int& 

يتم أيضًا استبدال نوع المعلمة نفسها. أعتقد أن هذا يرجع إلى حقيقة أنه لا يمكن للغة النظر في متغير lvalue مخصص في مكان ما فوق ما يمكن نقله أكثر. سنكتشف ذلك لاحقًا عندما نصل إلى روابط عالمية.
للتحقق من أن T مرجع مرجعي حقًا ، كتبت T myVar في نص وظيفة القالب ، والذي عرضه هذا T واستلم رسالة بشكل متوقع - "تم الإعلان عنها كمرجع ولكن لم تتم تهيئتها" - الرابط :)


قواعد الاستدلال ل rvalue


تنطبق القواعد "العادية" للفقرة 1.


 rvalue int —> (T &&param) —> int, param - int&& 

من الواضح بالفعل أنه يتم "تضمين" المراجع العالمية فقط لكائنات rvalue - المؤقتة ، في حالات أخرى ، عندما لا تكون الحجة مرجعًا عالميًا ، لا يتم تمييز rvalue ، lvalue


3. تمرير القيمة (كما هي)


عند المرور بالقيمة ، يتم تجاهل ثبات مرجعية الحجة الأصلية ومرجعيتها باعتبارها غير ضرورية لأن هذه كائنات مستقلة جديدة تمامًا ، لماذا يحتاجون إلى مؤهلات لما لا يرتبطون به؟


 int —> (T param) —> int const int —> (T param) —> int const int & —> (T param) —> int //       ,     const char * const —> (T param) —> const char * 

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

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


All Articles