Propagation de 'typedef' de la classe basée à la classe dérivée pour 'template'
-
10-07-2019 - |
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;
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>
où 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;