Bonjour,

Lorsque l'on utilise la nouvelle syntaxe pour les boucles en C++11, par exemple :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 : Sélectionner tout - Visualiser dans une fenêtre à part
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 : Sélectionner tout - Visualiser dans une fenêtre à part
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 : Sélectionner tout - Visualiser dans une fenêtre à part
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 : Sélectionner tout - Visualiser dans une fenêtre à part
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 Lua : Sélectionner tout - Visualiser dans une fenêtre à part
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 Lua : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
local array = {1, 2, 5, 0, -5, 5.2, 85};
for data in array do
    // ...
end