لماذا لا يتمكن فئة قالب مشتقة من الوصول إلى معرفات فئة قالب قاعدة؟

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

سؤال

انصح:

template <typename T>
class Base
{
    public:
        static const bool ZEROFILL = true;
        static const bool NO_ZEROFILL = false;
}

template <typename T>
class Derived : public Base<T>
{
    public: 
        Derived( bool initZero = NO_ZEROFILL );    // NO_ZEROFILL is not visible
        ~Derived();
}

أنا غير قادر على ترجمة هذا مع GCC G ++ 3.4.4 (Cygwin).

قبل تحويل هذه القوالب الفئة، كانت الفئة غير عامة كانت قادرة على رؤية الأعضاء الثابت للفئة الأساسية. هل هذه الخسارة من الرؤية في متطلبات المواصفات C ++ أم هل هناك تغيير بناء الجملة الذي أحتاج إلى توظيفه؟

أنا أفهم أن كل شىء Base<T> سيكون لديه عضو ثابت خاص "ZEROFILL" و "NO_ZEROFILL"، الذي - التي Base<float>::ZEROFILL و Base<double>::ZEROFILL متغيرات مختلفة، لكنني لا أهتم حقا؛ ثابت هو هناك للحصول على قابلية قراءة الرمز. كنت أرغب في استخدام ثابت ثابت لأن هذا أكثر آمنة من حيث النزاعات الاسم بدلا من ماكرو أو عالمي.

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

المحلول

هذا بحث مرحلتين بالنسبة لك.

Base<T>::NO_ZEROFILL (جميع معرفات CAPS BOO، باستثناء وحدات الماكرو، راجع للشغل) هي معرف يعتمد على T.
منذ ذلك الحين، عندما يقوم برنامج التحويل البرمجي أولا بتوزيع القالب، لا يوجد نوع فعلي T ومع ذلك، فإن المترجم لا "يعرف" ماذا Base<T> يكون. لذلك لا يمكن معرفة أي معرفات تفترض أن يتم تعريفها فيه (قد يكون هناك تخصص للبعض TS أن المترجم يرى لاحقا فقط) ولا يمكنك حذف مؤهل الفئة الأساسية من المعرفات المحددة في الفئة الأساسية.

لهذا السبب عليك أن تكتب Base<T>::NO_ZEROFILL (أو this->NO_ZEROFILL). التي تحكي المحول البرمجي ذلك NO_ZEROFILL هو شيء في الفئة الأساسية، والذي يعتمد على T, ، وأنه لا يمكن إلا التحقق من ذلك لاحقا، عند إنشاء مثيل للقالب. لذلك سوف يقبل ذلك دون محاولة التحقق من التعليمات البرمجية.
يمكن التحقق من هذا الرمز إلا في وقت لاحق، عند إنشاء القالب عن طريق تثبيت المعلمة الفعلية T.

نصائح أخرى

المشكلة التي واجهتها بسبب قواعد البحث عن الاسم للفصول الأساسية التابعة. 14.6 / 8 لديه:

عند البحث عن إعلان الاسم المستخدم في تعريف القالب، يتم استخدام قواعد البحث المعتادة (3.4.1، 3.4.2) للأسماء غير المصنفة. تم تأجيل البحث عن الأسماء المعتمدة على معلمات القالب حتى تعرف حجة القالب الفعلية (14.6.2).

(هذا ليس حقا "بحث 2 مرحلة" - انظر أدناه للحصول على شرح لذلك.)

الهدف حوالي 14.6 / 8 هو أنه فيما يتعلق بالمترجم NO_ZEROFILL في مثالك هو معرف ولا يعتمد على معلمة القالب. لذلك يبحث الأمر وفقا للقواعد الطبيعية في 3.4.1 و 3.4.2.

هذا البحث الطبيعي لا يبحث في الداخل Base<T> وهكذا no_zerofill هو مجرد معرف غير محدد. 14.6.2 / 3 لديه:

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

عندما تكون مؤهلا NO_ZEROFILL مع Base<T>:: في جوهرها، تقوم بتغييره من كونه اسما غير معتمد إلى واحد معتمد وعندما تقوم بذلك في تأخير بحثها حتى يتم إنشاء القالب.

ملاحظة جانبية: ما هو البحث 2 المرحلة:

void bar (int);

template <typename T>
void foo (T const & t) {
  bar (t);
}


namespace NS
{
  struct A {};
  void bar (A const &);
}


int main ()
{
  NS::A a;
  foo (a);
}

يتم تجميع المثال أعلاه على النحو التالي. التحويل البرمجي يوزع الجسم وظيفة foo ونرى أن هناك دعوة إلى bar التي لها حجة تعتمد (أي واحد يعتمد على معلمة القالب). في هذه المرحلة، يبحث المحول البرمجي عن شريط حسب 3.4.1 وهذا هو "بحث المرحلة الأولى". ستجد البحث وظيفة void bar (int) وهذا مخزن مع الدعوة التابعة حتى وقت لاحق.

عند إنشاء القالب إنشاء مثيل (نتيجة للاتصال main)، يقوم المترجم ثم بإجراء بحث إضافي في نطاق الحجة، وهذا هو "المرحلة 2 البحث". هذه الحالة التي تؤدي إلى العثور عليها void NS::bar(A const &).

يحتوي المترجم على اثنين من الزائد ل bar وينتشر بينهما، في حالة الاتصال أعلاه void NS::bar(A const &).

يبدو أن تجميع موافق في VS 2008. هل حاولت:

public:
    Derived( bool initZero = Base<T>::NO_ZEROFILL );

جرب هذا البرنامج

#include<iostream>
using namespace std;
template <class T> class base{
public:
T x;
base(T a){x=a;}
virtual T get(void){return x;}
};
template <class T>
class derived:public base<T>{
public:
derived(T a):base<T>(a){}
T get(void){return this->x+2;}
};
int main(void){
base<int> ob1(10);
cout<<ob1.get()<<endl;
derived<float> ob(10);
cout<<ob.get();
return 0;
}

في ال T get(void){return this->x+2;} يمكن أن تستخدم أيضا دقة النطاق (: :) المشغل. على سبيل المثال، حاول استبدال الخط مع

T get(void){return base<T>::x+2;}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top