Ce qui suit est un peu « mal », mais il nous a sauvé de nombreux bugs.
(Mise à jour, merci au commentaire de @ Ricky65 pour me ramener ici.) C++ 11 a un range-based for loop qui est de loin supérieur à ceci, si votre compilateur le supporte; nous travaillons toujours avec certains vraiment vieux compilateurs, cependant.
#define FOREACH(iter,stlContainer) \
for (typeof(stlContainer.begin()) iter = stlContainer.begin(), \
iter##End_Cached = stlContainer.end(); \
iter != iter##End_Cached; \
++iter)
(nouvelle mise à jour, le crédit aux devs Boost.) Il est vaguement basé sur le plus complexe mais plus capable BOOST_FOREACH
macro, mais a l'avantage d'être beaucoup plus facile à parcourir en debug pour les petits cas, et ne nécessitant pas un petit tas d'en-têtes boost (qui dans certaines bases de code/groupes est verboten).
L'utilisation std::for_each
est généralement préférable, mais a quelques inconvénients:
- utilisateurs doivent connaître beaucoup de choses sur les interactions entre
bind1st
/bind2nd
/ptr_fun
/mem_fun
à utiliser efficacement pour non-trivial "visite" - Boost corrige un grand nombre de ces problèmes, mais pas tout le monde a ou sait boost
- les utilisateurs peuvent avoir besoin de fournir leur propre foncteur séparé (généralement une structure) pour un seul point d'utilisation; les structures ne peuvent pas être déclarées dans la fonction entourant la boucle, ce qui conduit à une "non-localité" de code apparenté - elle ne se lit pas aussi bien que d'avoir la logique en ligne avec le flux du reste de la fonction dans certains cas
- il ne signifie pas toujours bien en ligne, selon le compilateur
La macro FOREACH comme indiqué ci-dessus fournit un certain nombre de choses:
- comme
std::for_each
, vous ne recevrez pas vos tests de limites mal (pas d'itération après la fin, etc.)
- il utilisera
const_iterators
sur des conteneurs constants
Notez qu'il nécessite une extension "typeof" quelque peu non standard.
Une utilisation typique pourrait être:
list< shared_ptr<Thing> > m_memberList;
// later
FOREACH(iter, m_memberList)
{
if ((*iter)->getValue() < 42) {
doSomethingWith(*iter);
}
}
Je ne suis pas entièrement satisfait de cette macro, mais il a été très précieux ici, en particulier pour les programmeurs sans que beaucoup d'expérience dans la conception STL-aware.
(S'il vous plaît ne hésitez pas à signaler avantages/inconvénients/défauts, je vais mettre à jour la réponse.)
Je trouve cette question vraiment utile. Il est cependant monté par quelques réponses inutiles ... +1 à tous ceux qui ont contribué. – AndreasT