2010-06-21 71 views
3

Je voudrais passer un conteneur arbitraire comme argument de fonction et le parcourir (pas d'effacement ni de poussée d'éléments). Malheureusement, il semble qu'il n'y ait pas de façon standard de le faire.Existe-t-il un équivalent C++ à l'interface de collection Java pour les classes de conteneur STL?

La première solution qui me vient à l'esprit est une interface (appelons-la CollectionInterface) implémentée par des classes qui vont envelopper les conteneurs STL. de sorte que la déclaration de fonction ressemblerait à ceci:

f(const CollectionInterface * collection); 

Ou, je pensais modèle de méthode, qui a un avantage qu'il maintient la liaison au moment de la compilation:

template <class CONTAINER> void f(const CONTAINER & collection); 

Quelle façon pensez-vous est mieux ?

Répondre

7

ForwardIterator? C'est un type de InputIterator (ou OutputIterator) qui permet également des algorithmes multi-passes (l'incrémentation n'invalide pas les valeurs antérieures).

Les itérateurs (qui sont assez différents des itérateurs Java) sont les threads centraux qui unifient les collections C++. Pour des exemples d'algorithmes fonctionnant sur eux (et les exigences de type itérateur associées), vous pouvez commencer par <algorithm>. En particulier, search fournit un exemple d'utilisation de ForwardIterator. Il trouve la première occurrence dans la plage [first1, last1] de la séquence définie par la plage [first2, last2). Ce sont tous des objets répondant aux exigences de ForwardIterator.

+0

En tant que paramètre pour un modèle de méthode? – doc

+0

@doc: Pour les fonctions de modèle, les fonctions libres ou membres sont souvent préférées en C++ si elles n'ont pas besoin d'être une fonction membre. –

4

Vous pouvez également écrire des méthodes qui acceptent le conteneur entier à la place d'une référence si c'est la façon dont vous voulez gérer les choses. Les itérateurs dans les conteneurs de bibliothèque standard sont tous fournis via les fonctions membres begin() et end(), ou dans certains cas rbegin() et rend() pour l'itération vers l'arrière. La façon dont les modèles fonctionnent, vous n'avez pas besoin de créer un type d'interface réel dont dérivent les objets; les exigences sont plutôt déduites par l'objet est utilisé.

template<typename Container> void Function(const Container& c) { 
    for(typename Container::const_iterator i = c.begin(), end = c.end(); i != end; ++i) 
     //do something 
} 

itérateurs Passing offrent une plus grande flexibilité lors de l'utilisation des fonctions, en particulier dans que tous les itérateurs proviennent de conteneurs avec explicites begin() et end() fonctions, et vous pouvez fournir toutes les sous-gamme explicite que vous voulez. Mais parfois cette méthode est appropriée.

+0

J'aime cette façon mais j'ai trouvé quelques problèmes.Je ne peux pas spécifier le type de contenu à l'intérieur du conteneur, et je reçois un avertissement «incapable de résoudre l'identificateur» lorsque j'accède à 'const_iterator',' begin() 'et' end() '. – Tony

4

Je voudrais passer un conteneur arbitraire en tant qu'argument de fonction et le parcourir (pas d'effacement ni de poussée d'éléments).

Passez les itérateurs. Voici un exemple de mise en œuvre et de l'utilisation:

template <typename Iter> 
void function(Iter begin, Iter end) 
{ 
    for (Iter it = begin; it != end; ++it) 
    { 
     std::cout << *it << std::endl; 
    } 
} 

int main() 
{ 
    std::string array[] = {"hello", "array", "world"}; 
    function(array, array + 3); 

    std::vector<std::string> vec = {"hello", "vector", "world"}; 
    function(vec.begin(), vec.end()); 
} 

Notez que dans de nombreux cas, vous n'avez pas réellement besoin d'écrire la fonction, mais vous pouvez le composer en utilisant les installations de la bibliothèque au lieu puis simplement appliquer std::for_each sur cette . Ou encore mieux, utilisez un algorithme préexistant comme std::accumulate ou std::find_if.