2009-12-17 8 views

Répondre

6

La méthode C++ consiste à utiliser des itérateurs. Tout comme toutes les fonctions <algorithm> qui prennent (it begin, it end,) comme deux premiers paramètres.

template <class IT> 
T foo(IT first, IT last) 
{ 
    return std::accumulate(first, last, T()); 
} 

Si vous voulez vraiment passer le conteneur lui-même à la fonction, vous devez utiliser les paramètres 'template template'. Cela est dû au fait que les conteneurs de bibliothèque standard C++ sont non seulement modélisés avec le type du type contenu, mais aussi avec un type d'allocateur, qui ont une valeur par défaut et sont donc implicites et non connus.

#include <vector> 
#include <list> 
#include <numeric> 
#include <iostream> 

template <class T, class A, template <class T, class A> class CONT> 
T foo(CONT<T, A> &cont) 
{ 
    return std::accumulate(cont.begin(), cont.end(), T()); 
} 

int main() 
{ 
    std::vector<int> v; 
    v.push_back(1); 
    v.push_back(2); 
    v.push_back(3); 

    std::list<int> l; 
    l.push_back(1); 
    l.push_back(2); 
    l.push_back(3); 

    std::cout << foo(v) << " " << foo(l) << "\n"; 

    return 0; 
} 
+1

Aussi, il est assez rare qu'il soit utile de prendre un conteneur génériquement. Les seules fonctions membres d'un conteneur sont begin, end, size, max_size, empty et swap. Si vous avez les itérateurs début/fin, vous pouvez faire tout cela sauf max_size (qui est presque inutile) et swap, bien que la taille puisse être beaucoup plus lente avec les itérateurs. Les conteneurs ont aussi différents types, dont la plupart peuvent être obtenus à partir des itérateurs de l'itérateur. Donc, en prenant n'importe quel conteneur sauve surtout la frappe. Être un peu plus spécifique (prendre une séquence, par exemple) pourrait être plus utile. –

1

Cela dépend de ce que vous voulez faire avec le conteneur. Une pensée: il suffit de passer un itérateur si vous voulez accéder à ce qui est stocké dans le conteneur.

1

Une bonne question, +1. Quel dommage, ses deux ans ... Je poste quand même une réponse: Tu es coincé avec la "manière C++" si tu ne veux qu'exposer une interface de ta bibliothèque. Ma façon de le faire est la suivante:

template<class TValue> 
class IEnumerator { 
public: 
    virtual bool MoveNext() = 0; 
    vírtual TValue Current() = 0; 
    virtual void Reset() = 0; 
}; 

template<class TValue> 
class IEnumerable { 
public: 
    virtual std::unique_ptr< IEnumerator<TValue> > GetEnumerator() const = 0; 
}; 

De cette façon, vous pouvez écrire des API du genre suivant:

void MyAPI(const IEnumerable<IMyLibAPIObject>& pSequence); 

Bien sûr, je fournit différentes implémentations comme StlEnumerator ou StlEnumerable, ou EnumeratorAdaptor<T, U> pour obtenir covariance comme en C# ...

Cheers,

Paul

Edit: Jusqu'à présent, je me suis retrouvé avec un type effaçant 'AnyEnumerator' et 'AnyEnumerable'. De plus, je suis conscient des diverses implémentations 'any_iterator' ...