Opérateur Typedef et Osstream pour un vecteur std ::
Question
J'ai créé un chromosome de classe qui a fini par être simplement un wrapper pour Vector avec un opérateur OSstream, j'ai donc décidé de Typedef Vector à la place. Cependant, j'ai des problèmes avec l'opérateur d'osstream modèle ... Est-ce la meilleure façon de procéder? (J'ai vu quelques approches et j'ai réussi à faire fonctionner)
template<typename G>
class Chromosome {
public:
typedef typename std::vector<G> type;
typedef typename std::pair<type *,type *> ptr_pair;
};
template<typename G> //line 19 below:
std::ostream& operator<<(std::ostream& os, const Chromosome<G>::type& chromosome) {
for(auto iter = chromosome.begin(); iter != chromosome.end(); ++iter)
std::cout << *iter;
return os;
}
Pour le moment, l'erreur que j'obtiens est:
chromosome.h:19: error: expected unqualified-id before ‘&’ token
chromosome.h:19: error: expected ‘)’ before ‘&’ token
chromosome.h:19: error: expected initializer before ‘&’ token
Acclamations.
La solution
Malheureusement, il n'y a pas de moyen propre de le faire car le compilateur ne peut pas déduire le type de G
de la déclaration de fonction
template<typename G>
std::ostream& operator<<(std::ostream& os, const typename Chromosome<G>::type& chromosome);
La raison en est que si vous deviez vous spécialiser Chromosome
Pour différents types, vous pourriez vous retrouver dans une situation où le compilateur ne pouvait pas déduire sans ambiguïté G
. Par exemple:
template <typename G> class Chromosome {
public:
typedef std::vector<G> type; // No typename needed here, BTW
};
template <> class Chromosome<int> {
public:
typedef std::vector<double> type;
};
Maintenant, que se passerait-il si vous faisiez cela?
vector<double> v;
cout << v << endl;
Le compilateur ne peut pas dire si G
est double
ou int
Dans ce cas, parce que les deux Chromosome<int>
et Chromosome<double>
ont vector<double>
comme leur type imbriqué.
Pour résoudre ce problème, vous devrez utiliser explicitement le type vector<G>
Comme l'argument:
template<typename G>
std::ostream& operator<<(std::ostream& os, const std::vector<G>& chromosome);
Malheureusement, il n'y a vraiment pas de meilleure façon de le faire. Ce n'est pas vraiment un défaut dans la langue, car il y a une bonne raison de l'interdire, mais cela vous empêche de faire ce que vous voulez dans ce contexte.
Autres conseils
Le membre Typedef type
est un nom dépendant: sa signification dépend du paramètre de modèle G
. Vous devez utiliser un typename
pour dire au compilateur que type
Nomme un type:
const typename Chromosome<G>::type&
Pour l'explication complète, envisagez de lire l'article de FAQ C ++ FAQ à débordement de pile, Où mettre le «modèle» et «typename» sur les noms dépendants.
Comme @TemplateTypeDef fait allusion aux commentaires, alors que cela permettra au code de compiler, cela ne "fonctionnera" pas pour vous permettre d'insérer un std::vector<G>
en un std::ostream
car type
est dans un contexte non conduit.
Le moyen le plus simple de déclarer la surcharge et d'obtenir le comportement attendu est d'utiliser std::vector<G>
directement comme type d'argument:
template<typename G>
std::ostream& operator<<(std::ostream& os, const std::vector<G>& chromosome)