Ungültige Verwendung eines unvollständigen Typs
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’
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();
}