Frage

Ich versuche, in meinem Projekt eine Typedef aus einer Unterklasse zu verwenden. Ich habe mein Problem im folgenden Beispiel isoliert.

Weiß jemand, wo ich falsch liege?

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;
}

Dies ist die Ausgabe, die ich bekomme:

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’
War es hilfreich?

Lösung

Der Grund dafür ist, dass beim Instanziieren einer Klassenvorlage auch alle ihre Deklarationen (nicht die Definitionen) ihrer Mitgliedsfunktionen instanziiert werden.Die Klassenvorlage wird genau dann instanziiert, wenn die vollständige Definition einer Spezialisierung erforderlich ist.Dies ist beispielsweise der Fall, wenn es wie in Ihrem Fall als Basisklasse verwendet wird.

Was also passiert, ist Folgendes A<B> wird instanziiert bei

class B : public A<B>

an welchem ​​Punkt B ist noch kein vollständiger Typ (er steht nach der schließenden Klammer der Klassendefinition).Jedoch, A<B>::action's Erklärung erfordert B Der Vollständigkeit halber, denn es kriecht in seinem Umfang:

Subclass::mytype

Was Sie tun müssen, ist, die Instanziierung bis zu einem bestimmten Punkt zu verzögern B ist komplett.Eine Möglichkeit hierfür besteht darin, die Deklaration von zu ändern action um daraus eine Mitgliedervorlage zu machen.

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

Es ist immer noch typsicher, denn if var ist nicht vom richtigen Typ, passt var Zu do_action wird versagen.

Andere Tipps

Sie können dieses Problem umgehen, indem Sie eine Züge-Klasse:
Es erfordert, dass Sie eine specialsed Merkmale Klasse für jede Klasse actuall einrichten Sie verwenden.

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;
} 

Sie leiten B von A<B>, so das erste, was der Compiler tut, sobald sie die Definition der Klasse B sieht, ist zu versuchen, A<B> zu instanziiert. Um dies zu tun, es für den Parameter von B::mytype bekannten action muss. Aber da der Compiler gerade im Begriff ist, von herauszufinden, die eigentlichen Definition von B aus, es nicht wissen, diese Art noch und eine Fehlermeldung angezeigt.

Ein Weg, um dies wäre der Parameter-Typ als ein anderes Template-Parameter zu erklären, statt in der abgeleiteten Klasse:

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> { ... };

Nicht genau, was Sie fragen, aber Sie können Aktion eine Vorlage Memberfunktion machen:

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;
}

Sie brauchen einen Zeiger oder eine Referenz als die richtige Art zu diesem Zeitpunkt nicht der Compiler nicht instanziiert kann es bekannt, verwenden.

Stattdessen versuchen:

void action(const typename Subclass::mytype &var) {
            (static_cast<Subclass*>(this))->do_action();
    }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top