c++ - هل ما زلنا بحاجة إلى كتابة الأقواس الزاوية الفارغة عند استخدام كائنات دالة شفافة؟




templates language-lawyer (2)

مع خصم وسيطة قالب الفصل ، يمكننا كتابة:

std::less Fn;

ومع ذلك ، يرفض G ++ 8.2 هذا الرمز:

#include <algorithm>
#include <vector>
#include <functional>

int main()
{
std::vector v= { 1, 3, 2, 7, 5, 4 };

std::sort(v.begin(),v.end(),std::greater());
}

انبعاث الخطأ التالي:

error: cannot deduce template arguments for 'greater' from ()

يقوم كلانج ++ 7.0 و MSVC 15.8.0 بتصنيفها دون تحذيرات. المترجم الذي هو الصحيح؟


دول مجلس التعاون الخليجي خطأ. هناك بالفعل تقرير الشوائب .

[dcl.type.simple]/2 يقول:

يعد محدد النوع الخاص typename للنموذج opt -name-name- typename opt opt -name هو عنصرًا نائبًا لنوع الفئة المستخلص ([dcl.type.class.deduct]).

و [dcl.type.class.deduct]/2 يقول:

يمكن أيضًا استخدام عنصر نائب لنوع فئة تم استنتاجه في type-specifier-seq في معرّف نوع جديد أو معرف نوع تعبير جديد ، باعتباره محدد نوع بسيط في تحويل نوع صريح (تدوين وظيفي ) ([expr.type.conv]) ، أو كمحدد للنوع في إعلان المعلمة لمعلمة القالب . يجب ألا يظهر عنصر نائب لنوع الفصل المستخلص في أي سياق آخر.

هذا الاستخدام مسموح به.

[temp.arg]/4 يصف خطأ بناء الجملة الذي يتطلب معرف القالب ولكن لا يوجد <> . ومع ذلك ، هنا لم يتم حل std::greater كمعرف قالب بحيث لا يتم تطبيق هذه الفقرة.


كلانج و MSVC صحيحة. يجب أن يكون هذا بشكل جيد بسبب تأثير مجموعة أدلة الاستنباط المولدة ضمنيًا (منذ C ++ 17) ووسيطة القالب الافتراضية.

(منجم التركيز)

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

  • إذا تم تعريف C ، لكل منشئ (أو قالب منشئ) Ci أعلن في القالب الأساسي المسمى (إذا تم تعريفه) ، يتم إنشاء قالب وظيفة خيالية Fi ، بحيث
    • معلمات القالب Fi هي معلمات القالب C متبوعة (إذا كانت Ci عبارة عن قالب مُنشئ) بواسطة معلمات القالب Ci ( يتم تضمين وسيطات القالب الافتراضية أيضًا )
    • المعلمات وظيفة فاي هي المعلمات منشئ
    • نوع الإرجاع Fi هو C متبوعًا بمعلمات القالب الخاصة بقالب الفصل الموجود في <>
  • إذا لم يتم تعريف C أو عدم إعلان أي مُنشئين ، فسيتم إضافة قالب وظيفة خيالية إضافي ، مشتق على النحو الوارد أعلاه من مُنشئ افتراضي C ()
  • في أي حال ، يضاف قالب وظيفة خيالية إضافية مشتقة أعلاه من منشئ افتراضي C (C) ، ودعا مرشح خصم نسخة.

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

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

بالنظر إلى std::greater() ، يتم تطبيق دليل الاستنتاج الضمني ويتم تحديد الوظيفة الخيالية الإضافية أخيرًا. كنتيجة لدقة التحميل الزائد ، يتم تطبيق void الوسيط الافتراضي ، ثم يكون النوع المستنتج void . هذا يعني أن std::greater() يجب أن يكون مثل الكتابة std::greater<void>() أو std::greater<>() .

BTW: Gcc لا يتم ترجمة مع std::greater() ، ولكن std::greater{} أو std::greater g; بخير ، قد يكون خطأ مجلس التعاون الخليجي.





argument-deduction