c++ de la classe de modèle; fonction arbitraire type de conteneur, comment le définir?
Bon, simple question. Dis-je définir ma classe de modèle à quelque chose comme ceci:
template<typename T>
class foo {
public:
foo(T const& first, T const& second) : first(first), second(second) {}
template<typename C>
void bar(C& container, T const& baz) {
//...
}
private:
T first;
T second;
}
La question est à propos de ma barre de fonction... j'en ai besoin pour être en mesure d'utiliser un conteneur standard, ce qui est pourquoi j'ai inclus le modèle/typename C partie, à définir ce type de conteneur. Mais apparemment ce n'est pas la bonne façon de le faire, depuis ma classe de test puis se plaint qu':
erreur: 'bar' n'a pas été déclarée dans ce cadre
Alors, comment pourrais-je aller sur la mise en œuvre de ma fonction de la barre de la bonne façon? C'est, en fonction de ma classe de modèle, avec l'arbitraire d'un type de conteneur... le reste de ma classe de modèle fonctionne très bien (il a d'autres fonctions qui ne sont pas d'entraîner une erreur), c'est juste qu'une fonction qui est problématique.
EDIT:
Ok, donc la fonction spécifique (la barre) est une eraseInRange fonction, qui efface tous les éléments dans une plage spécifiée:
void eraseInRange(C& container, T const& firstElement, T const& secondElement) {...}
Et un exemple de la façon dont elle sera utilisée serait:
eraseInRange(v, 7, 19);
où v est un vecteur dans ce cas.
EDIT 2:
Je suis bête! J'étais censé déclarer la fonction en dehors de ma classe, et non en lui... assez frustrant erreur à faire. De toute façon, merci à tous pour l'aide, mais le problème était un peu différent, l'information m'a aidé à construire la fonction, car après avoir trouvé mon problème d'origine, j'ai eu un autre agréable erreurs. Donc, je vous remercie!
Le code que vous avez posté compile bien. Où en êtes-vous réellement avoir le problème?
Votre classe de test n'arrive pas à la inherit de foo? Voir parashift.com/c++-faq-lite/modèles.html#faq-35.19
J'espère que mon montage efface un peu? La classe de test a été fournie pour l'exercice, de sorte que je ne devrais pas changer la façon dont la méthode est appelée, mais il se plaint de la eraseInRange mehtod pas être déclaré...
Puisque nous ne savons pas ce que votre pilote d'essai est en train de faire, nous ne pouvons pas les aider beaucoup. Ne le travail en classe pour vous, par exemple, si vous utilisez
eraseInRange
- vous avec un vecteur?OriginalL'auteur Fault | 2011-10-11
Vous devez vous connecter pour publier un commentaire.
Traits de solution.
Généraliser non plus que nécessaire, et pas moins.
Dans certains cas, cette solution pourrait ne pas être suffisante car elle correspond à un modèle, avec la signature (par exemple,
shared_ptr
), auquel cas vous pourriez faire usage detype_traits
, très bien comme en tapant duck (modèles de canard tapé en général).Un bon modèle n'est généralement pas restreindre artificiellement le genre de types pour lesquels ils sont valides (pourquoi devraient-ils?). Mais imaginez que dans l'exemple ci-dessus, vous devez avoir accès à l'un des objets
const_iterator
, alors vous pouvez utiliser SFINAE et type_traits de mettre ces contraintes sur votre fonction.Ou tout simplement pour que la bibliothèque standard ne
Généraliser non plus que nécessaire, et pas moins.
Pour plus de tels exemples, regarder dans
<algorithm>
.Cette approche de la force, c'est sa simplicité et est basé sur des concepts comme ForwardIterator. Il va même jusqu'à travailler pour les tableaux. Si vous souhaitez signaler des erreurs de droit dans la signature, vous pouvez les combiner avec des traits.
std
conteneurs avec signature commestd::vector
(pas recommandé)La solution la plus simple est approximée par Kerrek SB déjà, si elle n'est pas valide en C++. Le corrigé variante va comme suit:
Cependant: cela ne fonctionne que pour les conteneurs qui ont exactement deux type de modèle arguments, donc échouent lamentablement pour
std::map
(merci Luc Danton).Tout type de secondaire arguments de modèle (pas recommandé)
La version corrigée secondaire nombre de paramètre est comme suit:
Cependant: ce sera toujours pas pour les non-template des conteneurs (merci Luc Danton).
error: 'bar' was not declared in this scope
? Désolé, mais l'OP du code semble être la bonne. Je vois beaucoup de modèle de la magie, mais rien de tout cela est de savoir comment on accepte normalement un conteneur dans un modèle de fonction.Ce qui s'est passé à la programmation générique?
template<typename Container> void foo(Container& c) { /* use typename Container::value_type as needed etc. */ ...
Juste pour remarque: s'assurer au moment de la compilation que le Conteneur::value_type et T sont les mêmes (ou que le Conteneur est un conteneur) est le travail pour une charge statique de l'assertion. Comparer les diagnostics d'erreur que vous obtenez à partir des erreurs innocentes: ideone.com/gVVFU (comment utile est ça!) et ideone.com/ILIGP (avec le où et le pourquoi). Ce que vous voyez ci-dessus est seulement recommandé si vous allez à fournir une surcharge où ces types ne sont pas les mêmes, ou si le premier argument n'est pas un conteneur.
Rien ne s'est passé, et c'est encore la meilleure solution (voir la partie sur trait de vérifier dans ma réponse). Moi, j'ai été tenté par la perspective d'avoir une vraie phrase publié qui utilise le mot "modèle" quatre fois...
0) la Question a été
So how would I go about implementing my bar function the proper way?
. 1) Définir "normalement". La bibliothèque standard normalement fonctionne sur itérateur paires (ma quatrième proposition). E. g.std::count
's signature:count ( ForwardIterator first, ForwardIterator last, const T& value );
.OriginalL'auteur Sebastian Mach
Rendre le modèle basé sur un modèle sur un modèle de paramètre de modèle:
Si vous n'avez pas de C++11, alors vous ne pouvez pas utiliser les variadic templates, et vous devez fournir autant de paramètres du modèle de votre conteneur prend. Par exemple, pour une séquence récipient que vous pourriez avoir besoin de deux:
Ou, si vous voulez autoriser les allocateurs qui sont eux-mêmes des instances de modèle:
Comme je l'ai suggéré dans les commentaires, je préfère personnellement faire la totalité du conteneur basé sur un modèle type et l'utilisation des traits pour vérifier si il est valide. Quelque chose comme ceci:
C'est plus flexible car le conteneur peut maintenant être tout ce qui expose le
value_type
type de membre. Plus sophistiqué traits de vérification des fonctions de membre et itérateurs peut être conçu; par exemple, la jolie imprimante met en œuvre quelques-uns de ceux-ci.Toute justification pourquoi devrait fonctionner. (En général, cela doit être très rare chose à faire...)
Que voulez-vous dire? Vous pouvez faire correspondre toutes sortes de choses avec des modèles. Je ne dis pas que c'est la meilleure idée (personnellement, je serais probablement préférez pour un trait de vérifier de
typename C::value_type
), mais bon, c'est une option.Comment est-ce expliquer pourquoi le code ne marche pas (bien sûr, la question ne fournissent pas suffisamment d'informations) et pourquoi cela peut être attendus pour réussir? Il n'est même pas clair à partir de la question que T est censé être
C::value_type
. - Sans cette explication, cela sonne comme woodoo de programmation pour moi.Les Traits sont préférables, car ils permettent plus général des conteneurs. Avec le modèle de paramètre du modèle, vous devez anticiper le bon modèle de signature. Avec un trait de vérifier, vous pouvez avoir entièrement arbitraires conteneurs, tant qu'ils exposent
value_type
.OriginalL'auteur Kerrek SB
Voici la dernière version de cette réponse et une amélioration considérable de réponse par Sabastian.
L'idée est de définir tous les traits de conteneurs STL. Malheureusement, ce qui est difficile, très rapide, et heureusement, beaucoup de personnes ont travaillé sur le réglage du présent code. Ces traits sont réutilisables, il suffit donc de copier et passé de code ci-dessous dans le fichier appelé type_utils.hpp (n'hésitez pas à changer ces noms):
Maintenant vous pouvez utiliser ces traits de faire en sorte que notre code accepte uniquement les types de conteneurs. Par exemple, vous pouvez mettre en œuvre ajout de la fonction qui ajoute un vecteur à l'autre comme ceci:
Avis que je suis en utilisant begin() et end() de l'espace de noms std juste pour être sûr que nous avons itérateur comportement. Pour plus d'explication voir mon blog.
OriginalL'auteur ShitalShah