2009-10-28 6 views
2

Vu:passant std :: vecteur pour tout type à une fonction

template<typename T> class A { 
    B b; 
    std::vector<T> vec1; 
    std::vector<T> vec2; 
} 

Je voudrais B d'avoir une fonction de membre qui remplissent() qui prend une référence à ceux des vecteurs et remplit vec2 avec des valeurs de T en fonction de certaines informations contenues dans b.
Une façon de le faire est de remplir la surcharge() pour chaque argument possible T:

fill(const std::vector<float>& a, std::vector<float>& b) 

et ainsi de suite, mais cela signifie beaucoup de duplication inutile que les opérations sont les mêmes pour tous les possibles T. A l'intérieur de fill() Je pourrais utiliser vector :: value_type pour les calculs mais je ne sais pas comment le déclarer de telle sorte qu'il prenne tout type de std :: vector. La manière évidente serait d'utiliser une fonction gratuite avec des modèles. Y a-t-il une manière plus simple de faire ceci?

Répondre

5

B. créer des modèles à

template<typename T> class B { 
    void fill(const std::vector<T>& a, std::vector<T>& b) { } 
}; 

template<typename T> class A { 
    B<T> b; 
    std::vector<T> vec1; 
    std::vector<T> vec2; 
} 

Si vous ne voulez pas B créer des modèles à, puis la fonction créer des modèles à remplissage:

class B { 
    template<typename T> 
    void fill(const std::vector<T>& a, std::vector<T>& b) {} 
}; 
+1

Plus d'informations: B fait partie d'une hierachy d'héritage avec des fonctions virtuelles pures et enveloppé dans un pointeur intelligent à la classe de base. Les utilisateurs seraient invités à instancier B avec le même type que A (ce qui ajoute une possibilité d'erreur) et ne serait pas évident pour les utilisateurs des classes, donc je préfère éviter cela. – pmr

+0

Je réalise que refactoriser de grandes hiérarchies est un problème, mais vous pouvez également essayer d'utiliser une classe de politique comme paramètre de modèle au lieu de passer dans des pointeurs intelligents et apparemment (en fonction de votre description). –

4

fill créer des modèles à:

class B { 
public: 
    template<typename T> 
    void fill(const std::vector<T>& a, std::vector<T>& b) 
    { /*...*/ } 
    //... 
}; 

(A partir de votre description il voit que b devrait être un const std::vector<T>&.)

2

Vous pouvez définir B en tant que classe de modèle, remplir en fonction du modèle (dans une classe non-modèle B) ou, mon préféré, utilisez la norme std::transform/std::copy/std::fill, qui sont déjà fonction modèle, pour remplir votre vecteur.
(Tous situés à l'intérieur <algorithm> en-tête).

+0

Ne connaissait pas les fonctions de membre de modèle dans les classes non-template. Meilleure option jusqu'à présent avec std :: transform. – pmr

5

Vous avez obtenu un certain nombre de réponses, mais je ne suis pas d'accord avec elles, au moins dans une certaine mesure. Ma réaction immédiate est que vous ne devriez pas passer un vecteur à b::fill du tout. Au contraire, vous devriez passer un itérateur (ou peut-être une paire d'itérateurs). Le reste est la plupart du temps juste: cela signifie toujours fill devrait être une fonction de membre de modèle. Lorsque vous l'appelez, vous voudrez probablement passer un std::back_insert_iterator, généralement obtenu avec std::back_inserter.

Une partie de ce que vous avez dit semble contradictoire que: si b::fill et modifie vec1vec2, ils devraient probablement pas être passés comme des références à Const. Certes, const n'a pas exactement sa signification habituelle lorsqu'il est appliqué à un conteneur, mais il reste que passer une référence à const à une fonction dont la seule intention est apparemment de modifier ce qui est passé semble faux.

+1

D'accord Je suis d'accord avec le sentiment que vous devriez passer des plages d'itération plutôt que des conteneurs. Il devrait également vérifier l'effacement du type d'itérateur. Thomas Becker a une classe any_iterator tout comme la bibliothèque publique d'Adobe. –

+0

A propos des références à const: Seul le second vecteur sera modifié. A propos de l'utilisation des itérateurs: L'opération de remplissage sera plutôt lourde (beaucoup d'insertions) et elle peut bénéficier de vector :: reserve (int). Comment puis-je obtenir ce type d'amélioration des performances avec un std :: back_inserter? – pmr

+0

réserve des réserves _space_ (et aussi un du constructeur). il ne crée pas d'objet. vous pouvez utiliser reserve() et back_insert. Le résultat est la construction (ou l'assignation) d'un espace pré-alloué, ce qui est exactement ce que vous voulez. (et, pour les objets avec construction lourde et assignation légère, vous pouvez créer le vecteur avec la taille requise et ne pas utiliser back_inserter) –

Questions connexes