web-dev-qa-db-fra.com

std :: vector comme argument de fonction de modèle

Je veux faire une méthode de classe qui prend une référence std :: vector comme argument et je veux l'utiliser avec différents types de données.

La fonction devrait ressembler à:

void some_function(const std::vector & vect){ //do something with vector }

et je veux l'utiliser avec par exemple:

std::vector<int> v1;
some_function(v1);
std::vector<string> v2;
some_function(v2);

J'espère avoir clairement expliqué mon point de vue. Dois-je faire une méthode de modèle comme ça:

template<class T>
void some_function(std::vector<T> & vect){}

ou puis-je le faire d'une autre manière? Si je le dois, dites-moi comment je peux écrire cette méthode dans une classe.

Merci pour l'aide!

18
Prettygeek

La bonne façon pour une fonction template d'accepter tout std::vector Par const& Est:

template<typename T, typename A>
void some_func( std::vector<T,A> const& vec ) {
}

le deuxième argument est "l'allocateur", et dans une utilisation avancée de std::vector ce ne sera pas celui par défaut. Si vous acceptez simplement std::vector<T>, Votre some_func Rejettera std::vector Avec des allocateurs alternatifs.

Maintenant, il existe d'autres façons d'aborder cela que je vais énumérer rapidement. Je vais les énumérer dans un rapport coût/bénéfice décroissant - celui ci-dessus est probablement ce que vous voulez, et le suivant est parfois utile, et après cela je vais me lancer dans des cas sur-conçus qui valent rarement la peine d'être considérés (mais pourraient être utiles dans certains cas d'angle).

Vous pouvez accepter un type arbitraire T par T&& Puis tester pour déterminer si typename std::remove_reference<T>::type Est une sorte de std::vector. Cela vous permettrait de faire un "transfert parfait" du std::vector Entrant. Cela vous permettrait également de changer le prédicat que vous utilisez pour tester afin d'accepter plus qu'un simple std::vector: Pour la plupart, const& En std::vector A probablement juste besoin de quelques aléatoires arbitraires- conteneur d'accès.

Une façon ridiculement fantaisiste serait de faire une fonction en deux étapes. La deuxième étape prend une vue de plage à accès aléatoire effacée (ou simplement une vue de plage si vous n'avez pas besoin d'un accès aléatoire) pour un type fixe T avec SFINAE pour vous assurer que l'objet entrant est compatible, la première étape déduit le type de conteneur du type passé et appelle la deuxième étape dans un contexte SFINAE (auto some_func(...)->decltype(...)).

Comme l'effacement de type de std::vector<T> const& Dans une vue de plage à accès aléatoire de Ts contigus ne perd pas beaucoup de fonctionnalités, un avantage serait que vous pourriez garantir que le corps de votre fonction est exactement le même pour std::vector<T> const& et pour T[n] et pour std::array<T,n>.

Ce n'est pas un gros avantage, surtout pour le passe-partout requis.

c ++ 2 peut rendre cela beaucoup plus facile, car le SFINAE en plusieurs étapes ci-dessus se réduira en quelques clauses require.

31