J'écris une fonction d'utilité qui prendra un vecteur d'éléments (pourrait être une chaîne, int, une double, un char) et concaténer dans une seule chaîne et le renvoyer. Il ressemble à ceci: Je voudrais faire cette fonction plus générique: p>
vecteur
std :: vecteur
; code> avant
Quand je change les définitions ci-dessus en
std :: vecteur
vecteur code>,
list code>,
,
, code>,
deque code>, etc.) je veux faire la même chose comme ci-dessus. J'ai essayé de chercher cela à Stackoverflow et n'a pas trouvé de réponse satisfaisante. Li>
ul> p>
5 Réponses :
Étape 1, comme vous l'avez dit, utilisez des itérateurs:
template<typename container> std::string convert2Str(container const& vec) { using std::begin; using std::end; std::ostringstream sStream; for (auto it = begin(vec); it != end(vec); ++it) { typedef decltype(*it) T; // if needed sStream << *it << " "; } return sStream.str(); }
Quelle est la différence entre son point 1 et le vôtre. Utiliser STD :: Vecteur
@Ronny: C'est le mot-clé code> typename code> qui y est nécessaire. Le typeDEF est juste utilisé pour faciliter la transition vers un conteneur générique ( t code> et
code> est toujours défini, mais je chante lequel est l'argument de modèle).
Je suppose que la ligne "Typef conteneur :: value_type t; // si nécessaire" est ce qui indique au compilateur que le conteneur est un vecteur, une liste, etc. et garantit que Convert2Str ne peut pas être appelé avec un simple type de données tel que INT ou DOUBLE. Alors, pourquoi cette déclaration est-elle marquée "si nécessaire" .. Merci pour des réponses rapides.
@srikrish: cette ligne ne vous rappelle que le type t code> qui existait dans votre code d'origine. Cette fonction n'a pas utilisé
t code> n'importe où, mais je voulais vous montrer comment y accéder au cas où. Même sans cette ligne, si vous essayiez de passer quelque chose qui n'était pas un conteneur, le compilateur se plaint des appels à
commencez code> et
fin code>.
Donc, si T est un type défini par l'utilisateur (ma propre classe), puis-je faire quelque chose comme ce sstream << t.gevalue () << ""; ??
@Srikrish: Non, vous ne pouvez pas utiliser . code> après un type. Mais vous voudrez peut-être déclarer une variable locale de type
t code>, peut-être quelque chose comme
t somme = * it + 5; code>.
Je pense que cela devrait fonctionner: démo: http://ideone.com / 9puvv p> p>
Utilisez ceci. Vous avez besoin du typosame code> pour dire au compilateur qu'il devrait envisager
T :: const_itéator code> un type lors de l'analyse, il ne peut pas vraiment savoir que cela est vrai jusqu'à ce que vous Appelez effectivement la fonction qui passe quelque peu
t code> qui comporte un type
const_iterator code> type.
template<typename T>
std::string convert2Str(T const& cont)
{
std::ostringstream sStream;
for (typename T::const_iterator it = cont.begin(); it != cont.end(); ++it) {
sStream << *it << " ";
}
return sStream.str();
}
Bon point sur typename code>. Juste une autre raison de passer à C ++ 0x dès que possible.
C'est plus facile si vous vous clarifiez uniquement sur le type de conteneur. Le type de valeur est stocké dans tous les conteneurs standard, boost et qt en tant que membre Typedef code> MEMBRE
VALUE_TYPE CODE>.
std :: copier code> et
ostream_itéator code> vous permet de sauter les dernières déclarations d'itérateur.
template <typename Container>
std::string convert2Str(Container const &cont)
{
std::ostringstream s;
std::copy(cont.begin(), cont.end(),
std::ostream_iterator<typename Container::value_type>(s, " "));
return s.str();
}
Bien sûr, cela n'enseigne pas à Srikrish comment écrire une fonction générique de la sienne, ce qui est également une compétence utile. Et ostream_iterator
@BEN: déclinger code> est déroutant; On dirait que vous courez / évaluer une expression, alors que vous n'êtes pas vraiment. Tout conteneur compatible STL aura
valeur_type code> (les conteneurs standard font, les conteneurs de boost font et même ceux de QT).
@Larsman: Désolé, il devrait vraiment être ostream_iterator
valeur_type code>, mais ils fonctionnent avec
std :: commencent code> et
std :: end code>. Et il devrait définitivement être
en utilisant std :: copie; Copier (...); code> pour laisser la recherche de koenig faire sa chose. N'oubliez pas que les modèles de fonctions ne peuvent pas être partiellement spécialisés et définir de nouvelles surcharges dans
Nomspace std code> est interdit, le seul moyen de fournir une version optimisée de
copier code> pour un conteneur utilise ADL.
* Ce code est-il portable aux plates-formes telles que Solaris? J'ai récemment utilisé STD :: compter dans mon code et le compilateur Sun à Solaris se plaignit de cela. Pouvez-vous expliquer ce que fait cette déclaration "std :: ostream_iterator
@srikrish: cela fonctionne sur tout compilateur C ++ conformément à la norme, mais je ne sais pas si le compilateur Sun se conformait. Voir Cplusplus.com/reference/std/iterator/ostream_iterator .
Après la pratique STL, je vous recommanderais d'utiliser deux itérateurs pour les paramètres d'entrée, au lieu d'un conteneur (pour un motif évident de pouvoir fonctionner avec seulement une partie d'un conteneur, et généralement avec une séquence définie par les itérateurs):
std::vector<int> int_vec; std::list<float> f_list; std::deque<std::string> str_deq; // put something into the containers here std::cout<< convert2Str(int_vec.begin(), int_vec.end()) <<std::endl; std::cout<< convert2Str(f_list.begin(), f_list.end()) <<std::endl; std::cout<< convert2Str(str_deq.begin(), str_deq.end()) <<std::endl;