Comment gérer des iterateurs génériques en argument de fonction ?
4 réponses
meow
J'aimerai =E9crire une fonction foo(iterateur begin, iterateur end) qui
soit ind=E9pendante du type d'it=E9rateur donn=E9 (list, vector,
autre...) ... De base je pense =E0 un truc du genre :
template <class iterateur, class type> foo (iterateur<type>
b,iterateur<type> e) {
for (iterateur it=3Db;it!=3De;++it)
...
}
mais =E7a me semble bricolo... Il y a une fa=E7on propre de faire je
suppose.
J'aimerai écrire une fonction foo(iterateur begin, iterateur end) qui soit indépendante du type d'itérateur donné (list, vector, autre...)
template <class Iterateur> void f (Iterateur x, Iterateur fin) { for (; x != fin; ++x) { // faire quelque chose avec x } }
James Kanze
meow wrote:
J'aimerai écrire une fonction foo(iterateur begin, iterateur end) qui soit indépendante du type d'itérateur donné (list, vector, autre...) ... De base je pense à un truc du genre :
template <class iterateur, class type> foo (iterateur<type> b,iterateur<type> e) { for (iterateur it=b;it!=e;++it) ... }
mais ça me semble bricolo...
En plus, ça ne marcherait pas, parce que tu as déclaré iterateur comme un type, mais tu t'en sers comme un template.
Il existe des paramètres template des template, genre :
template< template < typename T > class Iter, type U > Iter< U > foo( Iter< U > ...
Mais je ne crois pas que ce soit ce que tu cherches : ça n'accepterait pas l'itérateur d'un vector, par exemple, qui n'est pas un template, mais un member d'un autre template, voire un typedef dans une classe templatée. (Aussi, je ne suis pas sûr que tous les compilateurs le supportent.)
La solution classique, comme a dit Fabien, c'est simplement :
template< typename Iter > Iter foo( Iter begin, Iter end ) { // ... }
Habituellement, on se sert du nom du type pour signaler les contraints : ForwardIterator, RandomAccessIterator, etc.
Ensuite, à l'intérieur de la fonction, on se sert de iterator_traits pour se renseigner des types apparentés, genre :
template< typename Iter > Iter foo( Iter begin, Iter end ) { assert( begin != end ) ; typename std::iterator_traits< Iter >::value_type first = *begin ++ ; // ... }
N'oublie pas le « typename » ; la norme l'exige, même si ce n'est pas forcement le cas de certains compilateurs.
Il y a une façon propre de faire je suppose.
Propre, je ne sais pas. C'est une question de goût. Mais ce que je viens de présenter est assez idiomatique, je crois.
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
meow wrote:
J'aimerai écrire une fonction foo(iterateur begin, iterateur end) qui
soit indépendante du type d'itérateur donné (list, vector,
autre...) ... De base je pense à un truc du genre :
template <class iterateur, class type> foo (iterateur<type>
b,iterateur<type> e) {
for (iterateur it=b;it!=e;++it)
...
}
mais ça me semble bricolo...
En plus, ça ne marcherait pas, parce que tu as déclaré iterateur
comme un type, mais tu t'en sers comme un template.
Il existe des paramètres template des template, genre :
template< template < typename T > class Iter, type U >
Iter< U >
foo( Iter< U > ...
Mais je ne crois pas que ce soit ce que tu cherches : ça
n'accepterait pas l'itérateur d'un vector, par exemple, qui
n'est pas un template, mais un member d'un autre template, voire
un typedef dans une classe templatée. (Aussi, je ne suis pas
sûr que tous les compilateurs le supportent.)
La solution classique, comme a dit Fabien, c'est simplement :
template< typename Iter >
Iter
foo( Iter begin, Iter end )
{
// ...
}
Habituellement, on se sert du nom du type pour signaler les
contraints : ForwardIterator, RandomAccessIterator, etc.
Ensuite, à l'intérieur de la fonction, on se sert de
iterator_traits pour se renseigner des types apparentés,
genre :
template< typename Iter >
Iter
foo( Iter begin, Iter end )
{
assert( begin != end ) ;
typename std::iterator_traits< Iter >::value_type
first = *begin ++ ;
// ...
}
N'oublie pas le « typename » ; la norme l'exige, même si ce
n'est pas forcement le cas de certains compilateurs.
Il y a une façon propre de faire je suppose.
Propre, je ne sais pas. C'est une question de goût. Mais ce que
je viens de présenter est assez idiomatique, je crois.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
J'aimerai écrire une fonction foo(iterateur begin, iterateur end) qui soit indépendante du type d'itérateur donné (list, vector, autre...) ... De base je pense à un truc du genre :
template <class iterateur, class type> foo (iterateur<type> b,iterateur<type> e) { for (iterateur it=b;it!=e;++it) ... }
mais ça me semble bricolo...
En plus, ça ne marcherait pas, parce que tu as déclaré iterateur comme un type, mais tu t'en sers comme un template.
Il existe des paramètres template des template, genre :
template< template < typename T > class Iter, type U > Iter< U > foo( Iter< U > ...
Mais je ne crois pas que ce soit ce que tu cherches : ça n'accepterait pas l'itérateur d'un vector, par exemple, qui n'est pas un template, mais un member d'un autre template, voire un typedef dans une classe templatée. (Aussi, je ne suis pas sûr que tous les compilateurs le supportent.)
La solution classique, comme a dit Fabien, c'est simplement :
template< typename Iter > Iter foo( Iter begin, Iter end ) { // ... }
Habituellement, on se sert du nom du type pour signaler les contraints : ForwardIterator, RandomAccessIterator, etc.
Ensuite, à l'intérieur de la fonction, on se sert de iterator_traits pour se renseigner des types apparentés, genre :
template< typename Iter > Iter foo( Iter begin, Iter end ) { assert( begin != end ) ; typename std::iterator_traits< Iter >::value_type first = *begin ++ ; // ... }
N'oublie pas le « typename » ; la norme l'exige, même si ce n'est pas forcement le cas de certains compilateurs.
Il y a une façon propre de faire je suppose.
Propre, je ne sais pas. C'est une question de goût. Mais ce que je viens de présenter est assez idiomatique, je crois.
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
meow
En fait, la solution de Fabien etait la première qui me soit venue à l'idée, mais j'étais assez dépité du fait qu'on y exprime pas le ty pe des objets pointés par l'itérateur. Et si je ne m'abuse la réponse "propre" est là :
typename std::iterator_traits< Iter >::value_type
Implementer le traits qui va bien :)
On va finir par faire quelque chose de bien avec moi ;) Merci à vous deux.
En fait, la solution de Fabien etait la première qui me soit venue à
l'idée, mais j'étais assez dépité du fait qu'on y exprime pas le ty pe
des objets pointés par l'itérateur.
Et si je ne m'abuse la réponse "propre" est là :
typename std::iterator_traits< Iter >::value_type
Implementer le traits qui va bien :)
On va finir par faire quelque chose de bien avec moi ;)
Merci à vous deux.
En fait, la solution de Fabien etait la première qui me soit venue à l'idée, mais j'étais assez dépité du fait qu'on y exprime pas le ty pe des objets pointés par l'itérateur. Et si je ne m'abuse la réponse "propre" est là :
typename std::iterator_traits< Iter >::value_type
Implementer le traits qui va bien :)
On va finir par faire quelque chose de bien avec moi ;) Merci à vous deux.
James Kanze
meow wrote:
En fait, la solution de Fabien etait la première qui me soit venue à l'idée, mais j'étais assez dépité du fait qu'on y exprime pas le type des objets pointés par l'itérateur. Et si je ne m'abuse la réponse "propre" est là :
typename std::iterator_traits< Iter >::value_type
Implementer le traits qui va bien :)
Dans ce cas-là, c'est la bibliothèque standard qui implémente les traits. Avec une implémentation par défaut qui prend des valeurs de la classe, et une spécialisation partielle pour les pointeurs (puisqu'on ne peut pas prendre des valeurs de la classe sans classe).
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
meow wrote:
En fait, la solution de Fabien etait la première qui me soit venue à
l'idée, mais j'étais assez dépité du fait qu'on y exprime pas le type
des objets pointés par l'itérateur.
Et si je ne m'abuse la réponse "propre" est là :
typename std::iterator_traits< Iter >::value_type
Implementer le traits qui va bien :)
Dans ce cas-là, c'est la bibliothèque standard qui implémente
les traits. Avec une implémentation par défaut qui prend des
valeurs de la classe, et une spécialisation partielle pour les
pointeurs (puisqu'on ne peut pas prendre des valeurs de la
classe sans classe).
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
En fait, la solution de Fabien etait la première qui me soit venue à l'idée, mais j'étais assez dépité du fait qu'on y exprime pas le type des objets pointés par l'itérateur. Et si je ne m'abuse la réponse "propre" est là :
typename std::iterator_traits< Iter >::value_type
Implementer le traits qui va bien :)
Dans ce cas-là, c'est la bibliothèque standard qui implémente les traits. Avec une implémentation par défaut qui prend des valeurs de la classe, et une spécialisation partielle pour les pointeurs (puisqu'on ne peut pas prendre des valeurs de la classe sans classe).
-- James Kanze (GABI Software) email: Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34