Solution de l’algorithme :
Solution pour boucle basé sur une plage :
Pourquoi voudrais-je utiliser le plus bavard `` plus basé sur une plage pour les boucles en C ++11 ?
Solution de l’algorithme :
Solution pour boucle basé sur une plage :
Pourquoi voudrais-je utiliser le plus bavard `` plus basé sur une plage pour les boucles en C ++11 ?
La première version
nous dit que vous voulez générer une séquence de valeurs.
Dans la deuxième version, le lecteur devra comprendre cela lui-même.
L’épargne sur le typage est habituellement sous-optimale, tel qu’il est le plus souvent perdu dans le temps de lecture. La plupart du code est lu beaucoup plus qu’il est tapé.
Personnellement, ma première lecture de:
std::generate(numbers.begin(), numbers.end(), rand);
"nous attribuons à tout un éventail. La gamme est numbers
. Les valeurs attribuées sont aléatoires".
Ma première lecture de:
for (int& x : numbers) x = rand();
"nous faisons quelque chose pour tout dans une gamme. La gamme est numbers
. Ce que nous faisons est d'attribuer une valeur aléatoire."
Ceux qui sont vachement similaire, mais pas identique. Une raison plausible pour que je veuille provoquer la première lecture, c'est parce que je pense que le fait le plus important à propos de ce code est qu'il attribue à la plage. Et voilà votre "pourquoi voudrais-je...". J'utilise generate
car en C++ std::generate
signifie "plage de cession". Comme btw n' std::copy
, la différence entre les deux est ce que vous êtes affectation à partir.
Il y a des facteurs de confusion. Gamme pour les boucles d'avoir une mesure plus directe manière d'exprimer que la plage est numbers
, que itérateur les algorithmes de le faire. C'est pourquoi les gens de travailler sur la gamme algorithme basé sur les bibliothèques: boost::range::generate(numbers, rand);
, c'est mieux que l' std::generate
version.
Contre qui, int&
dans votre gamme de boucle est une ride. Que faire si le type de valeur de la gamme n'est pas int
, alors nous sommes en train de faire quelque chose de gênant subtile ici qui en dépendent d'être transformable en int&
, alors que l' generate
code ne dépend que du retour de l' rand
être assignable à l'élément. Même si le type de valeur est int
, j'ai encore pourrait arrêter de penser, de savoir s'il est ou pas. Par conséquent auto
, ce qui reporte la réflexion sur les types jusqu'à ce que je vois ce qui est affectée -- auto &x
- je dire "prendre une référence à la gamme de l'élément, quel que soit le type que pourrait avoir". De retour en C++03, les algorithmes (parce qu'ils sont les modèles de fonction) ont été le moyen de masquer les types exacts, maintenant ils sont un moyen.
Je pense qu'il a toujours été le cas que le plus simple des algorithmes ont qu'un faible avantage, par rapport à l'équivalent des boucles. Gamme à base de boucles améliorer les boucles (principalement par la suppression de la plupart des passe-partout, bien qu'il y a un peu plus que ça). Donc, les marges de tirage serré et peut-être vous changez d'avis dans certains cas spécifiques. Mais il y a toujours une différence de style.
À mon avis, Efficace STL Article 43: "Préférez algorithme appels à écrit à la main boucles." est toujours un bon conseil.
J'ai l'habitude d'écrire des fonctions wrapper pour se débarrasser de l' begin()
/ end()
l'enfer. Si vous le faites, votre exemple ressembler à ceci:
my_util::generate(numbers, rand);
Je crois qu'il bat la gamme en fonction de boucle à la fois dans la communication de l'intention et de la lisibilité.
Cela dit, je dois avouer qu'en C++98, certains STL algorithme appels donné indicible code et à la suite de "Préfèrent l'algorithme appels à écrit à la main boucles" ne semble pas être une bonne idée. Heureusement, les lambdas ont changé.
Considérons l'exemple suivant de Herb Sutter: Λ, Λ Partout.
Tâche: Trouver le premier élément de v, c'est - > x
et < y
.
Sans lambdas:
auto i = find_if( v.begin(), v.end(),
bind( logical_and<bool>(),
bind(greater<int>(), _1, x),
bind(less<int>(), _1, y) ) );
Avec lambda
auto i=find_if( v.begin(), v.end(), [=](int i) { return i > x && i < y; } );
À mon avis, le manuel de la boucle, mais pourrait réduire le niveau de verbosité, manque de readabitly:
for (int& x : numbers) x = rand();
Je ne voudrais pas utiliser cette boucle pour initialiser1 de la plage définie par les nombres, parce que quand je le regarde, il me semble que c'est une itération sur une plage de numéros, mais en réalité, il ne l'a pas (en essence), j'.e au lieu de la lecture à partir de la gamme, il est écrit à la plage.
L'intention est beaucoup plus claire lorsque vous utilisez std::generate
.
1. initialiser dans ce contexte, signifie donner significative de la valeur pour les éléments du conteneur.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.