2015-08-04 3 views
3

Je dois effacer des éléments de différents conteneurs stl et boost par un itérateur. Parfois, j'ai aussi besoin de faire cela avec un reverse_iterator donc je voulais envelopper dans une fonction générique (set).Fonction d'effacement générique

Selon ce: Iterator invalidation rules il devrait surtout être possible.

Ce que je suis arrivé à ce jour est la suivante:

template<class T, bool T_IterReturned = helpers::EraseReturnsIterator<T>::value> 
    struct EraseImpl 
    { 
     typedef typename T::iterator iterator; 
     typedef typename T::const_iterator const_iterator; 
     static iterator erase(list& container, iterator it) { 
      return container.erase(it); 
     } 
     static const_iterator erase(list& container, const_iterator it) { 
      return container.erase(it); 
     } 
    }; 
    template<class T> 
    struct EraseImpl<T, false> 
    { 
     // This one gets used for e.g. std::set whos erase does not return 
     // an iterator until C++11 
     typedef typename T::iterator iterator; 
     typedef typename T::const_iterator const_iterator; 
     static iterator erase(list& container, iterator it) { 
      container.erase(it++); 
      return it; 
     } 
     static const_iterator erase(list& container, const_iterator it) { 
      container.erase(it++); 
      return it; 
     } 
    }; 

template<typename T> 
inline typename T::iterator erase(T& container, typename T::iterator it) 
{ 
    return detail::EraseImpl<T>::erase(container, it); 
} 

template<typename T> 
inline typename T::reverse_iterator erase(T& container, typename T::reverse_iterator it) 
{ 
    typename T::reverse_iterator tmp = it; 
    return typename T::reverse_iterator(erase(container, (++tmp).base())); 
} 

Cela devrait fonctionner pour la plupart des cas, mais par exemple un conteneur de type vectoriel qui ne renvoie pas l'itérateur le casserait. Les ensembles n'invalident pas les autres itérateurs -> ok pour utiliser le prochain itérateur. Pour les vecteurs, je devrais stocker l'itérateur précédent (le cas échéant) et le retourner. Pour un retour à l'itérateur (et similaire) sans cela, cela ne fonctionnera pas du tout. Je ne veux pas implémenter un EraseImpl pour tous les conteneurs connus, par ex. cela m'obligerait à inclure tous les en-têtes que je veux éviter.

Est-ce que je peux pour éviter pour tous spécialisés types? Bien sûr, je peux créer un trait avec une énumération comme {Use_Next, Use_Prev} et le laisser non spécialisé pour les conteneurs invalidant tous les itérateurs. Mais encore une fois: je ne veux pas inclure tous les en-têtes possibles.

+0

Vous n'avez pas besoin d'inclure tous les en-têtes, déclaration avant est suffisant pour les traits. – Jarod42

+1

@ Jarod42: Vous ne pouvez pas transmettre les types de bibliothèque standard. C'est pourquoi il y a un '' spécial. Cependant, c'est le seul en-tête de ce genre. – MSalters

+0

Je suppose qu'il n'y a pas de solution générale. Comment traiteriez-vous un conteneur qui invalide _all_ itérateurs sur 'erase'? Pas si farfelu; un contenant semblable à un vecteur qui rétrécit peut le faire. (Réallocation à un bloc plus petit) – MSalters

Répondre

0

Solution Je suis actuellement à l'aide est à l'aide d'une classe de caractères qui peuvent être spécialisés pour chaque classe de conteneur.

par défaut est « Non-autorisé », mais aussi de fournir des spécialisations pour les conteneurs qui ont une fonction d'effacement, qui retourne un itérateur. Ceci est fait de manière générique, donc seule l'existence d'une telle fonction est vérifiée. S'il est trouvé, generic_erase l'utilise. Si ce n'est pas le trait demande à l'utilisateur spécialisé qu'est ce que l'effacement fait aux itérateurs (next_iterator_valid, prev_iterator_valid, all_invalid) et generic_erase agit en conséquence.

cela a été utile pour cette tâche: Check for function signature also for inherited functions