Les ranged-base for loop apparues en C++11 sont un excellent moyen d'itérer sur l'ensemble des données d'un conteneur.
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 :
#include
template
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
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
};
Le code n'est certainement pas parfait mais vous donne une idée des possibilités. Prenez ceci comme une base.
Voici un exemple d'utilisation, pour afficher les nombres pairs sur [0,9] :
#include
#include
int main()
{
std::vector
for (int v : ForRangedLoopFilter
{
std::cout << v << std::endl;
}
return 0;
}
Pouvoir indiquer le filtre dans la déclaration de la boucle rend le code plus clair sur son but et utilisation selon moi.
Afin d'être utilisé avec un conteneur constant, il suffit d'ajouter un constructeur compatible :
#include
template
class ForRangedLoopFilter
{
...
public:
...
template
ForRangedLoopFilter(const Container& container, FilterFunc func)
: mContainer(const_cast
, mFilterFunction(func)
{}
...
};
Je garde la référence interne non constante afin de simplifier le code, je ne fais aucune modification du conteneur donc il n'y a pas de soucis.
#include
#include
#include
int main()
{
struct Toto {
int value;
std::string nom;
};
const std::vector
for (const Toto& v : ForRangedLoopFilter< std::vector
{
std::cout << v.value << ":" << v.nom << std::endl;
}
return 0;
}
Soutenez le club developpez.com en souscrivant un abonnement pour que nous puissions continuer à vous proposer des publications.