utilisation invalide de type incomplète
Je suis en train d'utiliser un typedef, à partir d'une sous-classe dans mon projet, j'ai isolé mon problème dans l'exemple ci-dessous.
Personne ne sait où je vais mal?
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;
}
C'est le résultat que j'obtiens:
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’
Vous devez vous connecter pour publier un commentaire.
La raison en est que lors de l'instanciation d'un modèle de classe, tous ses déclarations (pas les définitions) de ses fonctions de membre sont instanciés trop. Le modèle de classe est instanciée précisément lors de la définition complète d'une spécialisation est nécessaire. C'est le cas lorsqu'elle est utilisée comme classe de base par exemple, comme dans votre cas.
Ce qui se passe est que
A<B>
est instancié àà quel point
B
n'est pas complète type encore (c'est après l'accolade fermante de la définition de la classe). Cependant,A<B>::action
s'déclaration deB
pour être complet, parce qu'il est en train de ramper dans le champ d'application de celui-ci:Ce que vous devez faire est de retarder l'instanciation à un certain point à qui
B
est terminée. Une façon de le faire est de modifier la déclaration deaction
à en faire un membre de modèle.Il est toujours de type-safe, car si
var
n'est pas du bon type, en passantvar
àdo_action
échouera.Vous pouvez contourner ce problème en utilisant une classe de traits:
Elle nécessite de définir un specialsed classe de traits pour chaque actuall classe que vous l'utilisez.
Vous dérivez
B
deA<B>
, donc la première chose que le compilateur ne, une fois qu'il voit la définition de la classeB
est d'essayer d'instancierA<B>
. Pour ce faire, il doit connusB::mytype
pour le paramètre deaction
. Mais depuis que le compilateur est juste dans le processus de trouver la définition de laB
, il ne sait pas ce type encore et vous obtiendrez une erreur.Un moyen de contourner cela est de déclarer le type de paramètre comme un autre paramètre du modèle, au lieu de l'intérieur de la classe dérivée:
Pas exactement ce que vous demandez, mais vous pouvez rendre l'action d'un modèle de fonction de membre:
Vous avez besoin d'utiliser un pointeur ou une référence sur le type n'est pas connu à cette époque, le compilateur ne peut pas instancier.
Au lieu d'essayer: