Mais si l'on veut ne traiter que certaines entrées selon un critère/filtre, il faut alors ajouter le filtre dans la boucle afin de ne pas exécuter l'opération sur cette entrée, ce qui n'est pas très élégant.
En attendant une solution du langage, possiblement via les ranged, dans une version future, voici un moyen relativement simple de filtrer dans la boucle, en C++11 uniquement :
Code c++ : | Sélectionner tout |
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 | #include <functional> template<class Container> class ForRangedLoopFilter { using value_type = typename Container::value_type; using iterator = typename Container::iterator; public: friend class Iterator; class Iterator { public: Iterator(ForRangedLoopFilter& owner) : mOwner(owner) { mIterator = first(); } Iterator(ForRangedLoopFilter& owner, bool) : mOwner(owner) { mIterator = last(); } value_type& operator*() { return *mIterator; } value_type& operator->() { return *mIterator; } Iterator& operator++() { mIterator = next(); return *this; } bool operator !=(const Iterator& other) const { return mIterator != other.mIterator; } private: iterator first() { mIterator = mOwner.mContainer.begin(); if (!mOwner.mFilterFunction(*mIterator)) mIterator = next(); return mIterator; } iterator next() { do { mIterator++; } while (mIterator != last() && !mOwner.mFilterFunction(*mIterator)); return mIterator; } iterator last() { return mOwner.mContainer.end(); } private: ForRangedLoopFilter& mOwner; iterator mIterator; }; public: template<class FilterFunc> ForRangedLoopFilter(Container& container, FilterFunc func) : mContainer(container) , mFilterFunction(func) {} Iterator begin() { return Iterator(*this); } Iterator end() { return Iterator(*this, true); } private: Container& mContainer; std::function<bool(const value_type& entry)> mFilterFunction; }; |
Voici un exemple d'utilisation, pour afficher les nombres pairs sur [0,9] :
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | #include <iostream> #include <vector> int main() { std::vector<int> vec{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; for (int v : ForRangedLoopFilter<std::vector<int>>(vec, [](int v) { return v%2 == 0;})) { std::cout << v << std::endl; } return 0; } |
Afin d'être utilisé avec un conteneur constant, il suffit d'ajouter un constructeur compatible :
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include <functional> template<class Container> class ForRangedLoopFilter { ... public: ... template<class FilterFunc> ForRangedLoopFilter(const Container& container, FilterFunc func) : mContainer(const_cast<Container&>(container)) , mFilterFunction(func) {} ... }; |
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #include <iostream> #include <string> #include <vector> int main() { struct Toto { int value; std::string nom; }; const std::vector<Toto> vec{ {0, "toto"}, {1, "tata"}, {2, "titi"} }; for (const Toto& v : ForRangedLoopFilter< std::vector<Toto>>(vec, [](const Toto& v) { return v.value % 2 == 0; })) { std::cout << v.value << ":" << v.nom << std::endl; } return 0; } |