c++ - ما هو إجراء الترتيب الجزئي في خصم القالب



templates c++11 (1)

قرأت عن معيار c ++ 11 ولكن لا أستطيع أن أفهم جيدًا تفضيل النموذج التالي.

يتم استخدام مجموعتين من الأنواع لتحديد الترتيب الجزئي. لكل من القوالب المتضمنة هناك نوع الوظيفة الأصلي ونوع الوظيفة المحولة. [ملاحظة: يتم وصف إنشاء النوع المحول في 14.5.6.2. - ملاحظة النهاية] تستخدم عملية الاستنتاج النوع المحول كقالب وسيطة والنوع الأصلي للقالب الآخر كقالب للمعلمة. تتم هذه العملية مرتين لكل نوع يشارك في مقارنة الترتيب الجزئي: بمجرد استخدام القالب المحوّل -1 كقالب وسيطة و قالب 2 كقالب للمعلمة ومرة ​​أخرى باستخدام القالب المحول 2 كقالب وسيطة القالب -1 مثل قالب المعلمة
- N3242 14.8.2.4.2


بينما أعطى Xeo وصفاً جيداً في التعليقات ، سأحاول تقديم شرح تفصيلي مع مثال عملي.

أولاً ، الجملة الأولى من الفقرة التي اقتبستها تقول:

لكل من القوالب المتضمنة هناك نوع الوظيفة الأصلي ونوع الوظيفة المحولة . [...]

انتظر ، ما هو " نوع الوظيفة المتحولة "؟ توضح الفقرة 14-5-6-2 / 3 ما يلي:

لإنتاج القالب الذي تم تحويله ، لكل معلمة نوع ، أو غير نوع ، أو قالب (بما في ذلك حزم معلمات القالب (14.5.3)) ، قم بتوليف نوع فريد ، أو قيمة ، أو قالب فئة على التوالي ، واستبدله لكل تواجد لهذه المعلمة في نوع وظيفة القالب [...]

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

template<typename T, typename U>
void foo(T, U) // #1

الآن بما أن T و U هما نوعان من المعلمات ، فإن الفقرة المذكورة أعلاه تطلب منا اختيار وسيطة النوع المقابل لـ T (أيا كان) واستبداله في كل مكان في توقيع الدالة حيث تظهر T ، ثم القيام بنفس الشيء لـ U

الآن " تجميع نوع فريد " يعني أنه عليك اختيار نوع وهمي لم تستخدمه في أي مكان آخر ، ويمكننا أن نطلق عليه P1 (ثم ​​نختار P2 لـ U ) ، لكن ذلك سيجعل مناقشتنا رسمية بشكل غير مفيد.

دعنا فقط نقوم بتبسيط الأمور واختيار int لـ T و bool لـ U - نحن لا نستخدم هذه الأنواع في أي مكان آخر ، لذلك لأغراضنا ، فهي بنفس جودة P1 و P2 .

لذلك بعد التحويل ، لدينا:

void foo(int, bool) // #1b

هذا هو نوع الدالة المحولة لقالب الدالة foo() الأصلي الخاص بنا.

لذلك دعونا نستمر في تفسير الفقرة التي اقتبستها. الجملة الثانية تقول:

تستخدم عملية الاستنتاج النوع المحول كقالب وسيطة والنوع الأصلي للقالب الآخر كقالب للمعلمة. [...]

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

template<typename T>
void foo(T const*, X<T>) // #2

حيث X عبارة عن قالب طبقي خاص بنا.

الآن ما مع هذا القالب وظيفة الثاني؟ آه ، نعم ، نحن بحاجة إلى أن نفعل نفس الشيء الذي فعلناه سابقاً من أجل الزائد الأول من foo() وتحويله: مرة أخرى ، دعونا نختار حجة نوع لـ T ونستبدل T كل مكان. char هذا الوقت (نحن لا نستخدمه في أي مكان آخر في هذا المثال ، لذا هذا جيد مثل بعض P3 الوهمي):

void foo(char const*, X<char>) #2b

عظيم ، الآن لديه اثنين من القوالب الدالة وأنواع الدوال المحولة المقابلة. إذن ، كيف يمكن تحديد ما إذا كان #1 أكثر تخصصًا من #2 أو العكس؟

ما نعرفه من الجملة أعلاه هو أنه يجب مطابقة النماذج الأصلية وأنواع المهام التي تم تحويلها بطريقة أو بأخرى. ولكن كيف؟ هذا ما تشرحه الجملة الثالثة:

تتم هذه العملية مرتين لكل نوع يشارك في مقارنة الترتيب الجزئي: بمجرد استخدام القالب المحوّل -1 كقالب وسيطة و قالب 2 كقالب للمعلمة ومرة ​​أخرى باستخدام القالب المحول 2 كقالب وسيطة القالب -1 مثل قالب المعلمة

وبشكل أساسي ، يجب مطابقة نوع الوظيفة المحولة من القالب الأول ( #1b ) مع نوع دالة القالب الثاني الأصلي ( #2 ). وبالطبع في الاتجاه الآخر ، يجب مطابقة نوع دالة التحويل للقالب الثاني الثاني ( #2b ) مع نوع دالة القالب الأول الأصلي ( #1 ).

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

لنبدأ. بادئ ذي بدء ، سيتعين علينا مطابقة:

void foo(int, bool) // #1b

ضد:

template<typename T>
void foo(T const*, X<T>) // #2

هل هناك طريقة يمكننا من خلالها القيام بخصم نوع على T بحيث يصبح T const* int بالضبط وتصبح X<T> bool تمامًا؟ (في الواقع ، المطابقة التامة ليست ضرورية ، ولكن هناك استثناءات قليلة جدًا لهذه القاعدة وليست ذات صلة بغرض توضيح آلية الترتيب الجزئي ، لذا سنقوم بتجاهلها).

بالكاد. لذلك دعونا نحاول مطابقة العكس. يجب أن نطابق:

void foo(char const*, X<char>) // #2b

ضد:

template<typename T, typename U>
void foo(T, U) // #1

هل يمكننا استنتاج T و U هنا لإنتاج مطابقة char const* لـ char const* و X<char> ، على التوالي؟ بالتأكيد! انها تافهة. نحن فقط نختار T = char const* و U = X<char> .

لذلك اكتشفنا أن نوع الوظيفة المتحولة لأول عملية تحميل زائدة من foo() ( #1b ) لا يمكن مطابقتها مع نموذج الوظيفة الأصلي للحمولة الزائدة الثانية من foo() ( #2 )؛ من ناحية أخرى ، يمكن مطابقة نوع الدالة المحولة للحمولة الزائدة الثانية ( #2b ) مع نموذج الوظيفة الأصلي للحمولة الزائدة الأولى ( #1 ).

استنتاج؟ الزائد الثاني من foo() هو أكثر تخصصًا من الأول.

لاختيار مثال مضاد ، ضع في الاعتبار هذين القوالب الوظيفية:

template<typename T, typename U>
void bar(X<T>, U)

template<typename T, typename U>
void bar(U, T const*)

أي الزائد هو أكثر تخصصا من الآخر؟ لن أذهب من خلال الإجراء بأكمله مرة أخرى ، ولكن يمكنك القيام بذلك ، وهذا يجب أن يقنعك بأن مباراة لا يمكن أن تنتج في أي من الاتجاهين ، لأن الزائد الأول هو أكثر تخصصا من الثاني لأنه يتعلق بالمعلمة الأولى ، ولكن الثانية أكثر تخصصًا من الأولى فيما يتعلق بالمعلمة الثانية.

استنتاج؟ لا يوجد قالب وظيفي أكثر تخصصًا من الآخر.

الآن في هذا التفسير ، تجاهلت الكثير من التفاصيل والاستثناءات للقواعد والممرات الخفية في المعيار ، لكن الآلية المبينة في الفقرة التي اقتبستها هي في الواقع هذه الفقرة.

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

يتم تحديد ذلك في الفقرة 14.5.5.2/1 من معيار C ++ 11:

بالنسبة للمتخصصين الجزئيين في فئة القالب ، يكون الأول على الأقل متخصّصًا في التخصص الثاني ، إذا كان إعادة كتابة ما يلي إلى قاعدتي وظيفتين ، يكون قالب الوظيفة الأول على الأقل متخصّصًا كقالب ثان وفقًا لقواعد ترتيب قوالب الوظائف (14.5) .6.2):

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

- يحتوي قالب الوظيفة الثاني على نفس معلمات القالب مثل التخصص الجزئي الثاني ولديه معلمة دالة واحدة يكون نوعها هو تخصص قالب فئة مع وسيطات القالب للتخصص الجزئي الثاني.

آمل أن هذا ساعد.





template-deduction