[C++11] Range based loop : conserver la position dans le tableau ?
Bonjour,
Lorsque l'on utilise la nouvelle syntaxe pour les boucles en C++11, par exemple :
Code:
1 2 3 4 5
| std::vector<double> array(10);
for (auto data : array)
{
// ...
} |
... alors dans ce cas, data est de type double. On peut accéder à la valeur, mais une fois dans la boucle, on ne connaît pas a priori sa position dans le std::vector. Une solution est d'itérer sois-même à côté :
Code:
1 2 3 4 5 6 7 8
| std::vector<double> array(10);
size_t i = 0;
for (auto data : array)
{
// ...
++i;
} |
... mais on perd l'intérêt de la nouvelle syntaxe.
Du coup, j'ai implémenté moi-même quelque chose d'assez générique (j'ai condensé un peu le code pour que ça soit lisible sur le forum) :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
| template<class T>
class pairs_proxy
{
T& obj;
public :
pairs_proxy(T& t) : obj(t) {}
typedef typename T::iterator proxy_iterator;
typedef typename T::const_iterator proxy_const_iterator;
class iterator
{
proxy_iterator iter;
explicit iterator(proxy_iterator i) : iter(i) {}
public :
iterator() = default;
iterator& operator ++ () {
++iter; return *this;
}
iterator operator ++ (int) {
iterator tmp = *this; return ++tmp;
}
iterator& operator -- () {
--iter; return *this;
}
iterator operator -- (int) {
iterator tmp = *this; return --tmp;
}
proxy_iterator& operator * () {
return iter;
}
bool operator == (const iterator& i) const {
return iter == i.iter;
}
bool operator != (const iterator& i) const {
return iter != i.iter;
}
friend class const_iterator;
friend class pairs_proxy;
};
class const_iterator
{
proxy_const_iterator iter;
explicit const_iterator(proxy_const_iterator i) : iter(i) {}
public :
const_iterator() = default;
const_iterator(const iterator& i) : iter(i.iter) {}
const_iterator& operator ++ () {
++iter; return *this;
}
const_iterator operator ++ (int) {
const_iterator tmp = *this; return ++tmp;
}
const_iterator& operator -- () {
--iter; return *this;
}
const_iterator operator -- (int) {
const_iterator tmp = *this; return --tmp;
}
proxy_const_iterator& operator * () {
return iter;
}
bool operator == (const const_iterator& i) const {
return iter == i.iter;
}
bool operator != (const const_iterator& i) const {
return iter != i.iter;
}
friend class pairs_proxy;
};
iterator begin() {
return iterator(obj->begin());
}
iterator end() {
return iterator(obj->end());
}
const_iterator begin() const {
return const_iterator(obj->begin());
}
const_iterator end() const {
return const_iterator(obj->end());
}
};
template<class T>
pairs_proxy<T> pairs(T& t) {
return pairs_proxy<T>(t);
} |
On l'utilise alors comme suit :
Code:
1 2 3 4 5
| std::vector<double> array(10);
for (auto iter : pairs(array))
{
// ...
} |
... et c'est en réalité équivalent à l'itération "à l'ancienne" :
Code:
1 2 3 4 5
| std::vector<double> array(10);
for (auto iter = array.begin(); iter != array.end(); ++iter)
{
// ...
} |
Ma question est alors : existe-t-il déjà quelque chose dans le standard pour faire ce que je souhaite ?
Et si non, mon implémentation est-elle optimale à votre avis ? Que changeriez-vous ?
PS : Pour l'anecdote, le mot "pairs" est inspiré de Lua :
Code:
1 2 3 4 5
| local array = {1, 2, 5, 0, -5, 5.2, 85};
for idx, data in pairs(array) do
// 'idx' est l'indice sur lequel on itère (automatiquement)
// 'data' est la valeur de array[idx]
end |
Si on n'utilise pas pairs dans l'exemple ci-dessus, alors on perd l'information sur idx, et on retrouve une syntaxe très proche du premier morceau de code en haut de ce message :
Code:
1 2 3 4
| local array = {1, 2, 5, 0, -5, 5.2, 85};
for data in array do
// ...
end |