Question

J'essaie de définir la classe de base, qui contient uniquement la 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, en B, je reçois un message d'erreur indiquant que Vec_t n'est pas reconnu et que je dois l'écrire explicitement?

typename A<T>::Vec_t v;
Était-ce utile?

La solution

Je pense que cette question est dupliquée, mais je ne la trouve pas maintenant. C ++ Standard indique que vous devez qualifier complètement le nom conformément à 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, la portée de la classe de base n'est pas examinée lors de la recherche de nom non qualifiée soit au moment de la définition du membre ou du modèle de classe, soit lors d’une instanciation du membre ou du modèle de classe.

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

Autres conseils

Il existe quelque chose appelé dépendants et noms non dépendants dans le cas de modèles.

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

  

Voici la règle: le compilateur ne le fait pas   regardez dans les classes de base dépendantes (comme   A) quand on regarde non dépendant   noms (comme Vec_t). Par conséquent,   le compilateur ne sait même pas   existons encore moins sont des types.

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

La solution est donc d'utiliser le nom de type

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

Je vous recommande de consulter cette https://isocpp.org/ wiki / faq / templates # types de recherche de nom non indépendants .

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

Parce que le compilateur n'est pas certain que Vec_t nomme un type. Par exemple, A<T> peut être spécialisé pour T=int pour ne pas avoir ce typedef particulier.

Pour être complet, voici comment vous pouvez atténuer un peu cette nuisance:

  • re-typedef ces types dans les classes dérivées, ou mieux - comme avec méthodes -
  • importez simplement ces noms dans la portée de la classe dérivée avec un using declaration:
template<typename T>
class A
{
public:
    typedef std::vector<T> Vec_t;
};


template<typename T>
class B : public A<T>
{
public:
    using typename A<T>::Vec_t;
    // .........

private:
    Vec_t v;
};

Cela peut être utile si vous avez plus d'une mention du typedef hérité dans la classe dérivée. De plus, vous n'avez pas besoin d'ajouter typename à chaque fois.

Vous devez explicitement qualifier l'utilisation de Vec_t car le compilateur ne sait pas d'où <=> vient.

Il ne peut rien supposer sur la structure de A, car le modèle de classe A peut être spécialisé. La spécialisation peut inclure un <=> qui n'est pas une typedef ou même un membre <=>.

Vec_t n'est pas un nom dépendant, et le compilateur a besoin de savoir de quoi il s'agit sans instancier aucun modèle (la classe de base dans ce cas). Ce n'est vraiment pas 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é, car le nom ne dépend pas de l'argument de modèle T (pour autant que le compilateur puisse le supposer).

Dans l’ensemble, les modifications de type dans une classe de base de gabarit semblent plutôt inutiles pour une utilisation dans une classe dérivée. Les typedefs sont utiles pour l'utilisateur, cependant.

Ce concept peut être associé à la façon dont nous utilisons std::vector<T>. Par exemple, si nous avons un std::vector<int> Foo. Maintenant, nous décidons d'utiliser n'importe lequel de ses types de membres, disons un iterator. Dans ce scénario, nous mentionnons explicitement

std::vector<int>::iterator foo_iterator;

De même, dans votre cas, pour utiliser un type de membre public Vec_t sur template <typename T> class A, vous devez le déclarer explicitement comme

.
A<T>::Vec_t v;
OR
A<int>::Vec_t int_type;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top