سؤال

وأنا أحاول أن استخدام الرموز المميزة ل typedef من فئة فرعية في مشروعي، لقد عزل مشكلتي في المثال التالي.

لا أحد يعرف أين أنا ذاهب خاطئة؟

template<typename Subclass>
class A {
    public:
        //Why doesn't it like this?
        void action(typename Subclass::mytype var) {
            (static_cast<Subclass*>(this))->do_action(var);
        }
};

class B : public A<B> {
    public:
        typedef int mytype;

        B() {}

        void do_action(mytype var) {
            // Do stuff
        }
};

int main(int argc, char** argv) {
    B myInstance;
    return 0;
}

وهذا هو الإخراج أحصل على:

sean@SEAN-PC:~/Documents/LucadeStudios/experiments$ g++ -o test test.cpp
test.cpp: In instantiation of ‘A<B>’:
test.cpp:10:   instantiated from here
test.cpp:5: error: invalid use of incomplete type ‘class B’
test.cpp:10: error: forward declaration of ‘class B’
هل كانت مفيدة؟

المحلول

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

فما يحدث هو أن A<B> يتم إنشاء مثيل في

class B : public A<B>

والذي B نقطة ليس نوع يكتمل بعد (وهو بعد قوس الإغلاق للتعريف الفئة). ومع ذلك، يتطلب إعلان A<B>::action في B أن تكون كاملة، لأنه الزحف في نطاق ما يلي:

Subclass::mytype

ما عليك القيام به هو تأخير مثيل لمرحلة ما الذي B كاملة. طريقة واحدة للقيام بذلك هي لتعديل إعلان action لجعله قالب عضو.

template<typename T>
void action(T var) {
    (static_cast<Subclass*>(this))->do_action(var);
}

وومازال اكتب آمنة لأنه إذا var ليس من النوع الصحيح، ويمر var ستفشل في do_action.

نصائح أخرى

ويمكنك الحصول على حول هذا باستخدام فئة الصفات:
فإنه يتطلب منك إنشاء فئة الصفات متخصص من كل actuall الدرجة التي تستخدمها.

template<typename SubClass>
class SubClass_traits
{};

template<typename Subclass>
class A {
    public:
        void action(typename SubClass_traits<Subclass>::mytype var)
        {
                (static_cast<Subclass*>(this))->do_action(var);
        }
};


// Definitions for B
class B;   // Forward declare

template<> // Define traits for B. So other classes can use it.
class SubClass_traits<B>
{
    public:
        typedef int mytype;
};

// Define B
class B : public A<B>
{
    // Define mytype in terms of the traits type.
    typedef SubClass_traits<B>::mytype  mytype;
    public:

        B() {}

        void do_action(mytype var) {
                // Do stuff
        }
};

int main(int argc, char** argv)
{
    B myInstance;
    return 0;
} 

وأنت تستمد B من A<B>، وبالتالي فإن أول شيء المترجم لا، بمجرد أن يرى تعريف B الطبقة هو محاولة مثيل A<B>. للقيام بذلك فإنه يحتاج إلى B::mytype معروفة للمعلمة من action. ولكن منذ المترجم هو فقط في عملية معرفة التعريف الفعلي للB، فإنه لا يعرف هذا النوع حتى الان وتحصل على خطأ.

واحد سيلة للالتفاف حول ذلك هو سيكون للإعلان عن نوع المعلمة كمعلمة قالب آخر، بدلا من داخل فئة مشتقة:

template<typename Subclass, typename Param>
class A {
    public:
        void action(Param var) {
                (static_cast<Subclass*>(this))->do_action(var);
        }
};

class B : public A<B, int> { ... };

وليس بالضبط ما كنت طالبا، ولكن هل يمكن أن تجعل عمل دالة عضو القالب:

template<typename Subclass>
class A {
    public:
        //Why doesn't it like this?
        template<class V> void action(V var) {
                (static_cast<Subclass*>(this))->do_action();
        }
};

class B : public A<B> {
    public:
        typedef int mytype;

        B() {}

        void do_action(mytype var) {
                // Do stuff
        }
};

int main(int argc, char** argv) {
    B myInstance;
    return 0;
}

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

وبدلا من ذلك حاول:

void action(const typename Subclass::mytype &var) {
            (static_cast<Subclass*>(this))->do_action();
    }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top