c++ - static_assert يعتمد على معلمة قالب غير كتابة(سلوك مختلف على gcc و clang)




templates language-lawyer (2)

كلا المجمعين صحيحة. من [temp.res] / 8:

إذا لم يكن من الممكن إنشاء تخصص صالح لقالب ما ، ولم يتم إنشاء مثيل لهذا القالب ، فلن يتم تشكيل القالب بشكل سيء ، ولا يلزم التشخيص.

لا يوجد تخصص صالح يمكن إنشاؤه من القالب الأساسي Hitchhiker ، لذلك فهو غير صحيح ، ولا يلزم التشخيص. قرع يختار إصدار تشخيص على أي حال.

إذا كنت تريد فقط السماح بـ 42 ، فببساطة لا تحدد القالب العام:

template <int > struct Hitchhiker;
template <> struct Hitchhiker<42> {};
template <int answer> struct Hitchhiker {
  static_assert(sizeof(answer) != sizeof(answer), "Invalid answer");
};

template <> struct Hitchhiker<42> {};

أثناء محاولة تعطيل إنشاء مثيل عام للقالب مع static_assert ، اكتشفت أن الرمز أعلاه في clang يولد خطأ التأكيد حتى عندما لا يتم إنشاء مثيل للقالب ، بينما يولد gcc خطأ التأكيد فقط عند إنشاء مثيل لـ Hitchhiker مع معلمة غير 42 .

تافه من حولي وجدت أن هذا يؤكد:

template <int answer> struct Hitchhiker {
  static_assert(sizeof(int[answer]) != sizeof(int[answer]), "Invalid answer");
};

template <> struct Hitchhiker<42> {};

يتصرف نفس الشيء على كل من المترجمين: التأكيد يبدأ فقط عند إنشاء القالب العام.

ماذا يقول المعيار ، أي مترجم هو الصحيح؟

g++ 4.9.2
clang++ 3.50

ونقلت وجدت من قبلTartainLlama

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

N4296 [temp.res] / 8

ينطبق هذا مباشرة بعد تعريف القالب الأساسي (القالب الذي يحتوي على static_assert فيه). لذلك لا يمكن النظر في التخصص اللاحق (لـ 42 ) ، لأنه غير موجود حتى الآن.

والسؤال التالي هو ما إذا كان static_assert( sizeof(answer) != sizeof(answer), يعتمد على answer ، بمعنى أنه لا يفعل ذلك ، بناءً على ذلك بناءً عليه ، ومعايير حكيمة:

داخل القالب ، تحتوي بعض التركيبات على دلالات قد تختلف من مثيل إلى آخر. يعتمد هذا البناء على معلمات القالب.

N4296 [temp.dep] / 1

لا يختلف sizeof(answer) != sizeof(answer) الإنشاء sizeof(answer) != sizeof(answer) من إنشاء مثيل واحد إلى آخر. لذلك هذا البناء لا يعتمد على معلمات القالب. مما يعني أن static_assert بأكمله لا يعتمد على معلمة القالب.

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

قد تتسبب المحاولات sizeof(int[answer])!=sizeof(int[answer]) (مثل sizeof(int[answer])!=sizeof(int[answer]) إرضاء برنامج التحويل البرمجي الحالي للرب ، لكن لا يجعل البرنامج أكثر تنسيقًا.

يمكنك إثبات حالة من غير المحتمل أن يتمكن فيها المحول البرمجي من اللحاق بك ، ولكن تظل المشكلة غير صحيحة بصرف النظر عن قدرة المحول البرمجي على اللحاق بها. كقاعدة عامة ، تريد C ++ أن تترك لنفسها (ومترجميها) الحرية في العثور على رمز قالب غير صالح "أقدم من إنشاء مثيل" ؛ هذا يعني أن كود القالب يجب أن ينتج كودًا قانونيًا.

من الممكن أنك تريد شيءًا مثل =delete مع رسالة مرفقة.





dependent-name