سؤال

يجمع البرنامج التالي:

template <const int * P>
class Test{};

extern const int var = 42; //extern needed to force external linkage

int main()
{
    Test<&var> test;
}

هذا واحد, ومع ذلك, لا, وهي مفاجأة بالنسبة لي:

template <const int * P>
class Test{};

extern const int var = 42; //extern needed to force external linkage
extern const int * const ptr = &var; //extern needed to force external linkage
int main()
{
    Test<ptr> test; //FAIL! Expected constant expression.
}

مثال بديل:

int main()
{
   const int size = 42;
   int ok[*&size]; //OK

   const int * const pSize = &size;
   int fail[*pSize]; //FAIL
}

لقد خلصت إلى أن المؤشر لا يمكن أن يكون تعبيرا ثابتا بغض النظر عما إذا كان ثابتا وتهيئته بتعبير ثابت.

أسئلة:

  1. هل استنتاجي صحيح?
  2. لو ذلك, لماذا لا يمكن أن يكون المؤشر تعبيرا ثابتا?ان لم, لماذا لا تجمع البرامج المذكورة أعلاه?
  3. هل ج 0 0س (ج C 11, اذا صح التعبير) تغيير أي شيء?

شكرا على أي رؤى!

هل كانت مفيدة؟

المحلول

الأمر أكثر تعقيدا بعض الشيء.في 03 دولار كندي و 11 دولار كندي, &var هو تعبير ثابت إذا var هو ثابت محلي / فئة ثابت أو متغير نطاق مساحة الاسم.وهذا ما يسمى عنوان التعبير المستمر.يتم ضمان تهيئة متغير مؤشر نطاق ثابت أو نطاق مساحة الاسم مع هذا التعبير الثابت قبل تشغيل أي رمز (مرحلة التهيئة الثابتة) ، نظرا لكونه تعبيرا ثابتا.

ولكن فقط منذ 11 دولار كندي ، أ كونستكس متغير المؤشر الذي يخزن العنوان &var ويمكن أيضا أن تستخدم كتعبير ثابت عنوان وفقط منذ 11 ، يمكنك ديريفيرنس تعبير ثابت عنوان (في الواقع ، يمكنك ديريفيرنس أكثر - حتى عناوين عنصر صفيف المحلية ، ولكن دعونا يبقيه أونتوبيك) وإذا كان يشير إلى متغير لا يتجزأ ثابت تهيئة قبل ديريفيرنس أو متغير كونستكسر ، يمكنك مرة أخرى الحصول على تعبير ثابت (اعتمادا على نوع وقيمة الفئة ، وهذا النوع من التعبير المستمر قد تختلف).على هذا النحو ، فإن ما يلي صالح 11 دولارا أمريكيا:

int const x = 42;
constexpr int const *px = &x;

// both the value of "px" and the value of "*px" are prvalue constant expressions
int array[*px];
int main() { return sizeof(array); }

لو ذلك, لماذا لا يمكن أن يكون المؤشر تعبيرا ثابتا?ان لم, لماذا لا تجمع البرامج المذكورة أعلاه?

هذا قيد معروف في صياغة المعيار-فهو يسمح حاليا فقط بمعلمات القالب الأخرى كوسيطات أو & object, ، لمعلمة قالب من نوع المؤشر.على الرغم من أن المترجم يجب أن يكون قادرا على فعل المزيد.

نصائح أخرى

لا يزال غير مسموح به بمبلغ 0 دولار كندي. temp.arg.nontype يتطلب:

يجب أن تكون وسيطة القالب لمعلمة قالب غير من النوع وغير القالب واحدة من:

  • بالنسبة لمعلمة قالب غير من النوع المتكامل أو نوع التعداد ، تعبير ثابت تم تحويله (5.19) من نوع معلمة القالب;أو
  • اسم معلمة قالب غير من النوع;أو
  • تعبير ثابت (5.19) الذي يعين عنوان كائن مع مدة تخزين ثابتة و الربط الخارجي أو الداخلي أو وظيفة ذات ارتباط خارجي أو داخلي ، بما في ذلك قوالب الوظائف ومعرفات قالب الوظيفة ولكن باستثناء أعضاء الفئة غير الثابتة, أعرب (تجاهل الأقواس) على النحو التالي & id-expression, ، باستثناء أنه قد يتم حذف & إذا كان الاسم يشير إلى دالة أو مصفوفة ويجب يتم حذفها إذا كانت معلمة القالب المقابلة مرجعا;أو
  • تعبير ثابت يتم تقييمه إلى قيمة مؤشر فارغة (4.10);أو
  • تعبير ثابت يتم تقييمه إلى قيمة مؤشر عضو فارغ (4.11);أو
  • مؤشر للعضو معبرا عنه كما هو موضح في 5.3.1.

الجواب الأصلي:

  1. في ج 0 03 ، يمكن أن تكون التعبيرات المتكاملة فقط تعبيرات ثابتة.
  2. لأن المعيار يقول ذلك (بشكل طبيعي).
  3. في سيx 0س ، ن 3290 يتضمن أمثلة باستخدام constexpr على مؤشر.لذا يجب أن يكون ما تحاول الآن ممكنا ، على الرغم من أنه يجب عليك الآن استخدام constexpr الكلمة الرئيسية بدلا من المستوى الأعلى const.

هناك أيضا خلل في دول مجلس التعاون الخليجي, ز rejects يرفض أمثلة المسودة القياسية الخاصة بالصلاحية constexpr الاستخدام.

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

والأسوأ من ذلك ، في المثال الخاص بك ، كنت تأخذ عنوان متغير على المكدس!انظر الى هذا:

void myfunction( unsigned int depth) {
     const int myvar = depth;
     const int * const myptr = &myvar;
     if (depth)
         myfunction(depth-1);
}

إذا المكالمات الرئيسية ميفونكتيون (3) ، ثم يتم إنشاء 3 ميفارس في مواقع منفصلة.لا توجد طريقة لوقت الترجمة حتى تعرف كيف كثير يتم إنشاء ميفار ، ناهيك عن المواقع الدقيقة.

أخيرا:إعلان متغير ليكون const يعني:"أعدك" ، ويفعل لا يعني هذا هو ثابت وقت الترجمة.انظر هذا المثال:

int main(int argc, char** argv) {
    const int cargc = argc;
    char* myargs[cargc]; //the size is constant, but not a _compile time_ constant.
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top