سؤال

ممكن مكررة
لماذا لا يمكنني الحصول على عضو ثابت غير متكامل ثابت في الفصل؟

struct Example
{
    static const int One = 1000; // Legal
    static const short Two = 2000; // Illegal
    static const float Three = 2000.0f; // Illegal
    static const double Four = 3000.0; // Illegal
    static const string Five = "Hello"; // Illegal
};

هل هناك أي سبب له # 2، # 3، # 4، # 5 غير قانوني؟

أعتقد أنني أعرف سبب # 5: يحتاج المحول البرمجي إلى كائن سلسلة "حقيقي" (نظرا لأنه ليس نوعا مبنيا) ولا يمكن أن يستطيع الذهن Five مع "Hello" كما لو كان #define Five "Hello". وبعد ولكن إذا كان الأمر كذلك، فلا يمكن للمترجم يترك تلميحا في ملفات .obj وأخبر رابط إنشاء مثيل واحد تلقائيا من string Five مكان ما؟

ل # 3 و # 4 وخاصة # 2 (LOL!) ... لا أستطيع أن أرى حقا أي سبب ممكن! يطفو وضاعف أنواع مدمجة، تماما كما هو int! وقصير هو مجرد عدد صحيح أقصر (ربما).


تعديل: أنا أستخدم Visual Studio 2008 لتجميعها. اعتقدت أن جميع المترجمين تصرفوا نفس الشيء في هذه الحالة، ولكن على ما يبدو G ++ يجمعون أن الغرامة (باستثناء # 5). الأخطاء vs يعطي لهذا القصاصات هي:

 خطأ C2864: "مثال: : أربعة ': يمكن تهيئة أعضاء البيانات غير المتكاملة فقط في غضون خطأ فئة C2864: "مثال: خمسة فقط": يمكن تهيئة أعضاء البيانات الثابتة فقط في فئة
هل كانت مفيدة؟

المحلول

INT والاختصار قانوني، وإذا كان برنامج التحويل البرمجي الخاص بك لا يسمح لهم بعد ذلك هو تمثال نصفي:

9.4.2 / 4: ... إذا كان عضو البيانات الثابتة هو من نوع التعداد غير المتكامل أو المضغوط، فقد يحدد إعلانه في تعريف الفصل تهيئة ثابتة التي يجب أن تكون تعبيرا ثابتا لا يتجزأ.

أعتقد أن السبب الذي لا يعالجه العوامات والضاعف بشكل خاص كصواعد في معيار C ++، في الطريقة التي تكون بها الأنواع المتكاملة، هي أن المعيار C ++ هو حذر أن العمليات الحسابية على تعويم ومضاعف يمكن أن تكون مختلفة بشكل كبير على تجميع الجهاز، مما هي على الجهاز ينفذ الكود. بالنسبة للمترجم إلى تقييم تعبير ثابت مثل (A + B)، يحتاج إلى الحصول على نفس الإجابة التي سيحصل عليها وقت التشغيل.

هذا ليس الكثير من القضية مع Ints - يمكنك محاكاة الحساب الصحيح بشكل رائع نسبيا إذا كان يختلف. ولكن بالنسبة للمترجم إلى محاكاة الأجهزة العائمة على الجهاز المستهدف قد يكون صعبا للغاية. قد يكون ذلك مستحيلا، إذا كانت هناك إصدارات مختلفة من الرقاقة، ولا يعرف المترجم الذي سيتم تشغيله الرمز. وهذا حتى قبل أن تبدأ العبث مع وضع التقريب IEEE. لذلك تجنب المعيار الذي يتطلبه الأمر، بحيث لا يتعين عليه تحديد متى وكيف يمكن أن يختلف تقييم الوقت في وقت التقييم من تقييم وقت التشغيل.

كما يذكر براين، سيكون C ++ 0x معالجة هذا مع constexpr. وبعد إذا كنت على حق الدافع الأصلي، فمن المفترض أن 10 سنوات كانت طويلة بما يكفي للعمل من خلال الصعوبات في تحديد هذه الأشياء.

نصائح أخرى

كلاهما Example::One و Example::Two يجب أن تجميعها لك، وأنها تقوم بالفعل بتجميعها بالنسبة لي في نفس البيئة التي ذكرتها (مقابل 2008).

أنا لا أصدق Example::Three, ، و Example::Four يجب أن تجميع على الإطلاق في C ++ القياسية، ولكن أعتقد أن هناك امتدادا دولية في دول مجلس التعاون الخليجي يسمح بذلك. Example::Five لا ينبغي أن تجميع.

يمكنك تهيئة لهم مثل هذا بعد إعلان الهيكل، عادة في ملف المصدر الخاص بك:

const float Example::Three = 2000.0f;
const double Example::Four = 3000.0;
const string Example::Five = "Hello";

هذه هي الطريقة الأكثر محمولة للقيام بذلك، والطريقة التي أوصي بها القيام بذلك حتى لو كان برنامج التحويل البرمجي الخاص بك يسمح لك بتحديد Example::Three و Example::Four في إعلانك.

سيكون هناك خيار آخر هو إرجاع القيمة ببساطة من وظيفة ثابتة لنفس النوع.

struct Example
{
    //...
    static double Four() { return  = 3000.0; }
    //...
};

هذه الإجابة يناقش سبب محتمل أيضا.
هذه الإجابة يناقش كيف سيساعد معيار C ++ القادم عبر Constexpr

# 1 و 2 متوافقة مع المعيار. لسوء الحظ، بعض المترجمين ببساطة لا تتفق. لهذا السبب، على سبيل المثال، كان على مصممي دفعة تقديم وحدات ماكرو مزعجة مثل BOOST_STATIC_CONSTANT لتوليد مكتبات محمولة. إذا كنت لا ترغب في تحديد الثابت في ملف .cpp، فإن الحل البديل هو استخدام enum. وبعد على الرغم من أنه من الواضح أنه ليس لديك أي ضمان عن النوع، ولا يمكنك استخدام العوامات.

في C ++ 98، يمكن تهيئة أعضاء STAT CONST فقط من الأنواع المتكاملة في الفصل، ويجب أن يكون التهيئة تعبيرا ثابتا. تضمن هذه القيود أن نتمكن من القيام بالتهيئة في تجميع الوقت.

يرى مهنة الأعضاء في الفصل.

§9.4.2 أعضاء البيانات الثابتة

إذا كان عضوا ثابتا للبيانات ثابتا أو غير متكامل نوع التعداد، فيمكن إعلانه في الفصل الدراسي تحديد المهيمة الثابتة التي يجب أن يكون تعبيرا ثابتا ثابتا (5.19). في هذه الحالة، يمكن أن يظهر العضو في تعبيرات ثابتة متكاملة. لا يزال يعتبر العضو في نطاق مساحة الاسم إذا تم استخدامه في البرنامج ويجب عدم احتواء نطاق مساحة الاسم.

تحت VS2008 أحصل على الخطأ التالي:

1>.\Weapon Identification SystemDlg.cpp(223) : error C2864: 'Example::Three' : only static const integral data members can be initialized within a class
1>.\Weapon Identification SystemDlg.cpp(224) : error C2864: 'Example::Four' : only static const integral data members can be initialized within a class
1>.\Weapon Identification SystemDlg.cpp(225) : error C2864: 'Example::Five' : only static const integral data members can be initialized within a class

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

إعادة تهيئة النقطة العائمة، فإن المواصفات C ++ 98 لديها هذا (5.19):

يمكن أن تظهر حرفيات العائمة إلا إذا كانت مصنفة إلى أنواع متكاملة أو تعداد.

كما وجد الآخر، يحظر C ++ Standard تهيئة عضو ثابت ثابت مع قيمة نقطة عائمة.

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

هذه القدرة موجودة في الأجهزة الحقيقية. على سبيل المثال، فقط، يحتوي Intel X86 على بضعة بت في سجل مراقبة النقطة العائمة التي تتحكم في دقة حسابات النقاط العائمة. بشكل افتراضي، يتم إجراء الحسابات على نوع مزدوج 80 بت، وتقريب فقط إلى شيء مثل تعويم مزدوج أو 32 بت عند 64 بت عند الطلب. يمكن تعديل هذه البتات في السجل أثناء التنفيذ، لذلك (على سبيل المثال) "1.23" في مكان واحد يمكن أن تهيئة متغير إلى قيمة واحدة، في حين أن "1.23" في جزء آخر من البرنامج (بعد تعديل الدقة) قد ينتج في قيمة مختلفة (قليلا).

على الأقل كما أعرف، لا يزال هذا إمكانية نظرية، على الأقل في معظم الآلات النموذجية. على الرغم من أن أجهزة Intel يسمح بالضبط الديناميكي بدقة FP، لا أعرف من أي مترجم (لا حتى Intel) الذي يحاول اتخاذ مثل هذا التعديل في الاعتبار عند ترجمة حرفي FP (على الرغم من أن مترجم Intel يقوم على الأقل بدعم طويلة 80 بت نوع مزدوج).

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top