68 votes

Propagation de "typedef" de la classe de base à la classe dérivée pour "template".

J'essaie de définir une classe de base qui ne contient que des typedef.

template<typename T>
class A
{
public:
    typedef std::vector<T> Vec_t;
};

template<typename T>
class B : public A<T>
{
private:
    Vec_t v;  // fails - Vec_t is not recognized
};

Pourquoi, dans B, je reçois une erreur indiquant que Vec_t n'est pas reconnu et que je dois l'écrire explicitement ?

typename A<T>::Vec_t v;

0 votes

12 votes

En fait, il ne s'agit pas vraiment d'une copie exacte puisque l'article que vous mentionnez parle d'une méthode alors que celui-ci parle d'un type.

2 votes

Typename A::Vec_t v ; est parfait. Pas besoin de <T> ici

45voto

Kirill V. Lyadvinsky Points 47627

Je crois que cette question est dupliquée, mais je ne la trouve pas. La norme C++ indique qu'il faut qualifier complètement le nom conformément à l'article 14.6.2/3 :

Dans la définition d'un modèle de classe ou d'un membre d'un modèle de classe, si une classe de base du modèle de classe dépend d'un paramètre de modèle, l'attribut la portée de la classe de base n'est pas examinée lors de la recherche de noms non qualifiés soit au moment de la définition du modèle de classe ou du membre, soit lors de l'instanciation du modèle de classe ou du membre.

UPD : J'ai finalement trouvé un doublon : le voici .

24 votes

D'ailleurs, cela m'a toujours dérangé de devoir tout retaper... ce n'est pas agréable, pas agréable du tout.

14 votes

Btw vous n'avez pas besoin de tous les arguments du modèle et tout, lors de la qualification. En raison du nom de la classe injectée, il suffit d'écrire typename B::Vec_t

0 votes

@JohannesSchaub-litb J'essaie de faire comme vous l'avez dit, mais j'obtiens des erreurs si je ne spécifie pas les paramètres du modèle pour B. (B n'est pas une classe, un espace de noms ou une énumération).

42voto

Xinus Points 7693

Il existe une notion de dépendance et de non indépendant dans le cas de modèles.

Si le nom dépend du paramètre de modèle T, son dépendante et d'autres qui ne dépendent pas du paramètre T sont indépendant noms.

Voici la règle : le compilateur ne fait pas de regarde pas dans les classes de base dépendantes (comme A) lorsqu'il recherche des noms non dépendants (comme Vec_t). En conséquence, le compilateur n'a pas besoin de chercher dans les classes de base dépendantes (comme A), le compilateur ne sait même pas qu'elles encore moins qu'il s'agit de types.

Le compilateur ne peut pas supposer que Vec_t est un type jusqu'à ce qu'il sache que T parce qu'il existe une spécialisation potentielle des A<T>A<T>:: Vec_t est un est un membre des données

La solution est donc d'utiliser typename

 typename A<T>::Vec_t v;  ← good

Je vous recommande de lire ce qui suit https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-types .

Ancien lien (cassé) : http://www.parashift.com/c++-faq-lite/templates.html#faq-35.18

1 votes

Votre réponse était la seule qui semblait apporter une solution en plus d'une explication. Je vous remercie.

0 votes

Je vous offre un +1 si vous me signalez que vous avez corrigé le lien.

8voto

Jesse Beder Points 14026

Parce que le compilateur n'est pas certain que Vec_t nomme un type. Par exemple, A<T> peut être spécialisée pour T=int a no ont cette particularité typedef .

0 votes

Pour T une variable de type, A<T> est simplement déclaré à l'avance, il n'a pas de définition. Il n'y a que A<t>t est un type (et non une variable de type) peut être défini (en spécialisant une définition de modèle ou par une spécialisation explicite). En d'autres termes, même si l'on supprimait les spécialisations explicites et partielles des modèles en C++ (sans rien changer d'autre), ce ne serait toujours pas correct.

2voto

Paul Baker Points 3231

Vous devez qualifier explicitement l'utilisation de Vec_t car le compilateur ne sait pas où se trouve Vec_t provient de.

Il ne peut rien supposer de la structure de A, puisque le modèle de classe A peut être spécialisé. La spécialisation peut inclure un Vec_t qui n'est pas un typedef, ou il peut même ne pas inclure un membre Vec_t du tout.

1voto

UncleBens Points 24580

Vec_t n'est pas un nom dépendant, et le compilateur doit savoir ce que c'est sans instancier aucun modèle (classe de base dans ce cas). Ce n'est pas vraiment différent de :

template <class T>
class X
{
    std::string s;
}

Ici aussi, le compilateur doit connaître std::string même si X n'est pas instancié, puisque le nom ne dépend pas de l'argument de template T (pour autant que le compilateur puisse le supposer).

En fin de compte, les typedefs d'une classe de base template semblent plutôt inutiles pour une utilisation dans une classe dérivée. Les typedefs sont cependant utiles pour l'utilisateur.

0 votes

Voulez-vous dire class X : T { ici ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X