التعداد C ++ لم يتم التعرف عليه بشكل صحيح بواسطة برنامج التحويل البرمجي

StackOverflow https://stackoverflow.com/questions/681518

سؤال

هل يمكن لأي شخص أن يشرح لماذا لا يتم تجميع الكود التالي (على G ++ (GCC) 3.2.3 20030502 (Red Hat Linux 3.2.3-49))؟

struct X {
public:
   enum State { A, B, C };

   X(State s) {}
};

int main()
{
   X(X::A);
}

الرسالة التي أحصل عليها هي:

JJJ.CPP: في الوظيفة "int main ()":
JJJ.CPP: 10: "XX :: A" ليس عضوًا ثابتًا في "Struct X"
JJJ.CPP: 10: لا توجد وظيفة مطابقة للاتصال بـ "X :: X ()"
jjj.cpp: 1: المرشحون هم: x :: x (const x &)
jjj.cpp: 5: x :: x (x :: state) ``

هل هذا الرمز السيئ أم علة المترجم؟

مشكلة حلها نيل+كونراد. انظر التعليقات على إجابة نيل أدناه.

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

المحلول

X(X::A);

يُرى إعلان وظيفة ASA. إذا كنت تريد حقًا هذا الرمز ، فاستخدم:

(X)(X::A);

نصائح أخرى

لقد نسيت الاسم المتغير في تعريفك:

int main()
{
   X my_x(X::A);
}

يربك الرمز الخاص بك المترجم لأنه لا يمكن أن يميز هذا عن إعلان الوظيفة (العودة X ويمر X::A كحجة). عندما تكون في شك ، يقوم برنامج التحويل البرمجي C ++ دائمًا بإزالة الغموض لصالح الإعلان.

الحل هو تقديم قوسين زائدين حول X نظرًا لأن المترجم يمنع الأقواس حول الأنواع (على عكس مكالمات البناء وما إلى ذلك):

(X(X::A));

فقط لجعله واضحا ما يحدث. انظر إلى هذا المثال

int main() {
    float a = 0;
    {
        int(a); // no-op?
        a = 1;
    }
    cout << a;
}

ماذا ستخرج؟ حسنًا ، سوف يخرج 0. ال int(a) يمكن تحليلها أعلاه بطريقتين مختلفتين:

  • يلقي إلى int وتجاهل النتيجة
  • إعلان متغير يسمى a. لكن تجاهل الأقواس حول المعرف.

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

الآن ، قضيتك هي بالضبط. أنت تحاول (عن طريق الخطأ) إعلان معرف يسمى A ضمن فصل يسمى X:

X (X::A); // parsed as X X::A;

ثم يمتد المترجم إلى أنين حول مُنشئ افتراضي غير معلن ، لأن الثابت ، كما يفترض أنه ، تم إنشاؤه الافتراضي. ولكن حتى لو كان لديك مُنشئ افتراضي لـ X ، فلا يزال بالطبع خطأ لأنه لا A هو عضو ثابت في X ، ولا يمكن تعريف/إعلان ثابت من X في نطاق الكتلة.

يمكنك أن تجعله ليس تبدو وكأنها إعلان عن طريق القيام بعدة أشياء. أولاً ، يمكنك Paren التعبير كله ، مما يجعله لا يبدو وكأنه إعلان بعد الآن. أو فقط Paren النوع الذي يلقي. تم ذكر كل من هذه الأزياء في إجابات أخرى:

(X(X::A)); (X)(X::A)

هناك غموض مشابه ، ولكنه متميز عندما تحاول إعلان كائن بالفعل. انظر إلى هذا المثال:

int main() {
    float a = 0;
    int b(int(a)); // object or function?
}

لان int(a) يمكن أن يكون كل من إعلان معلمة تسمى a والتحويل الصريح (المصبوب) للمتغير العائم إلى INT ، يقرر المترجم مرة أخرى أن هذا إعلان. وبالتالي ، فإننا نعلن عن وظيفة تسمى b, ، والتي تأخذ حجة عدد صحيح ويعيد عدد صحيح. هناك العديد من الاحتمالات كيفية إزالة الغموض التي ، بناءً على الغموض أعلاه:

int b((int(a))); int b((int)a);

يجب أن تعلن كائن

X x(X::A);

خطأ في الكود الخاص بك.

أي من هذين الخطين يعملان بالنسبة لي:

X obj(X::A);
X obj2 = X(X::A);

كما يشير نيل بتروورث ، X(X::A) يتم التعامل معها كإعلان وظيفة. إذا كنت تريد حقًا كائن مجهول ، (X)(X::A) سوف بناء كائن X وحذفه على الفور.

يمكنك ، بالطبع ، أن تفعل شيئًا كهذا:

int main()
{
    // code
    {
    X temp(X::A);
    }
    // more code
}

سيكون هذا أكثر قابلية للقراءة وله نفس التأثير.

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