Outils pour utilisateurs

Outils du site


lang:cpp:boucles

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
lang:cpp:boucles [2019/12/26 13:56] – Ajout de la boucle for c++17 rootlang:cpp:boucles [2020/06/16 15:00] (Version actuelle) – Précision sur le style fonctionnel root
Ligne 1: Ligne 1:
-====Toutes les boucles====+=====Boucle sur des données (old style)===== 
 +====Conteneur supportant les index====
  
-===La boucle traditionnelle=== 
-  * Intervalle 
 <code cpp> <code cpp>
-for (int i = 0; i < 100; i++) +std::array<int, 4> arr { 10, 20, 30, 40 }; 
-  std::cout << i << std::endl;+for (size_t i = 0; i < arr.size(); i++) 
 +  std::cout << arr[i<< std::endl;
 </code> </code>
  
-Chaque paramètre est optionnel :+====Conteneur supportant les itérateurs====
 <code cpp> <code cpp>
-int i = 0+std::vector<int> vector{ 10, 20, 30, 40 }; 
-for (;;) + 
-{ +// Lecture / écriture 
-  if (>= 100+std::vector<int>::iterator it
-    break;+for (it = vector.begin()it != vector.end()it++
 +  (*it)++; 
 + 
 +// Lecture seule 
 +std::vector<int>::const_iterator itc; 
 +for (itc vector.cbegin(); itc != vector.cend(); itc++
 +  std::cout << *itc << std::endl; 
 +</code> 
 + 
 +=====Programmation fonctionnelle===== 
 + 
 +====for each==== 
 + 
 +===Conteneur de type primitif=== 
 + 
 +<code cpp> 
 +std::array<int, 4> arr = { 10, 20, 30, 40 }; 
 +// Ici, on utilise const & pour conserver le style fonctionnel. 
 +// Mais passer en copie un type primitif n'est pas plus penalisant que d'utiliser une référence. 
 +for (const int& i : arr)
   std::cout << i << std::endl;   std::cout << i << std::endl;
-  i++; 
-} 
 </code> </code>
  
-Et sa version ''while'' :+===Conteneur de type non primitif=== 
 <code cpp> <code cpp>
-int i 0+std::set<std::string> set { "10", "20", "30", "40" }; 
-while (100)+ 
 +for (const std::string& val : set) 
 +  std::cout << val << std::endl; 
 +</code> 
 + 
 +===Conteneur multi-types (map, tuple, ...)=== 
 + 
 +<code cpp> 
 +std::map<int, long> map { {10, 10}, {20, 20}, {30, 30}, {40, 40} }
 + 
 +// L'utilisation de auto est obligatoire. 
 +// const s'applique sur toutes les variables. 
 +for (const auto & [key, value] : map) 
 +  std::cout << value << std::endl; 
 +</code> 
 + 
 +L'interprétation par le compilateur sera : 
 + 
 +<code cpp> 
 +std::map<int, long> map = std::map<int, long, std::less<int>, std::allocator<std::pair<const int, long> > >{std::initializer_list<std::pair<const int, long> >{std::pair<const int, long>{10, 10}, std::pair<const int, long>{20, 20}, std::pair<const int, long>{30, 30}, std::pair<const int, long>{40, 40}}, std::less<int>(), std::allocator<std::pair<const int, long> >()};
 { {
-  std::cout << << std::endl+  std::map<int, long, std::less<int>, std::allocator<std::pair<const int, long> > > & __range1 = map; 
-  i++;+  std::_Rb_tree_iterator<std::pair<const int, long> > __begin1 = __range1.begin()
 +  std::_Rb_tree_iterator<std::pair<const int, long> > __end1 = __range1.end(); 
 +  for(; __begin1.operator!=(__end1); __begin1.operator++())  
 +  { 
 +    const std::pair<const int, long> & __operator9 = __begin1.operator*(); 
 +    std::tuple_element<0, const std::pair<const int, long> >::type& key = std::get<0UL>(__operator9); 
 +    std::tuple_element<1, const std::pair<const int, long> >::type& value = std::get<1UL>(__operator9); 
 +    std::cout.operator<<(value).operator<<(std::endl); 
 +  }
 } }
 </code> </code>
  
-  * Conteneur supportant les index :+===Implémentation sur une classe personnalisée=== 
 + 
 +Il faut définir l'itérateur et la classe à parcourir. [[https://www.cprogramming.com/c++11/c++11-ranged-for-loop.html|C++11 range-based for loops]] {{ :lang:cpp:boucles:range-based_for_loops_in_c_11_-_cprogramming.com_2019-12-26_12_35_03_.html |Archive le 26/12/2019}} 
 + 
 +Dans l'idéal, ''DataSample'' devrait prendre une classe en ''template'' plutôt que la classe ''Data'' en dur. 
 + 
 +Il faut commencer par déclarer l'itérateur.
  
 <code cpp> <code cpp>
-std::array<int, 4> arr 10203040 }; +#include <iostream> 
-for (size_t i = 0; i < arr.size(); i+++ 
-  std::cout << arr[i<< std::endl;+class DataSample; 
 + 
 +// Données accessibles depuis la boucle. 
 +class Data 
 +
 + public: 
 +  int getA() const { return a; } 
 +  void setA(int aa) { a = aa; } 
 + 
 + private: 
 +  int a; 
 +}; 
 + 
 +// Itérateur accessible en écriture. 
 +class Iter 
 +
 + public: 
 +  Iter(DataSample &p_vecint pos) : _pos(pos), _p_vec(p_vec) {
 + 
 +  bool operator!=(const Iter &other) const { return _pos != other._pos; } 
 +  Data &operator*(); 
 +  Iter &operator++() 
 +  { 
 +    ++_pos; 
 +    return *this; 
 +  } 
 + 
 + private: 
 +  int _pos; 
 +  DataSample &_p_vec; 
 +}; 
 + 
 +// Iterateur accessible uniquement en lecture. 
 +class ConstIter 
 +
 + public: 
 +  ConstIter(const DataSample &p_vecint pos) : _pos(pos)_p_vec(p_vec) {} 
 + 
 +  bool operator!=(const ConstIter &other) const { return _pos != other._pos; } 
 +  const Data &operator*() const; 
 +  const ConstIter &operator++() 
 +  { 
 +    ++_pos; 
 +    return *this; 
 +  } 
 + 
 + private: 
 +  int _pos; 
 +  const DataSample &_p_vec; 
 +}; 
 + 
 +// Classe stockant les données et implémentant le pattern for each. 
 +class DataSample 
 +
 + public: 
 +  // Méthodes accessibles en écriture. 
 +  Data &get(int col) { return _data[col]; } 
 +  Iter begin() { return Iter(*this0); } 
 +  Iter end() { return Iter(*this, 100)} 
 +  // Méthodes accessibles uniquement en lecture seule. 
 +  const Data &get(int col) const { return _data[col]; } 
 +  ConstIter begin() const { return ConstIter(*this, 0); } 
 +  ConstIter end() const { return ConstIter(*this, 100); } 
 + 
 +  void set(int index, int val) { _data[index].setA(val);
 + 
 + private: 
 +  // Dans cette classe, les données sont sous forme d'un tableau. 
 +  Data _data[100]; 
 +}; 
 + 
 +Data &Iter::operator*() { return _p_vec.get(_pos);
 +const Data &ConstIter::operator*() const { return _p_vec.get(_pos);
 + 
 +// Exemple d'usage. 
 +int main() 
 +
 +  DataSample v; 
 +  for (int i = 0; i < 100; i++) 
 +  { 
 +    v.set(i, i); 
 +  } 
 +  // Utilisation de begin et end en non const. 
 +  // Le type de retour est Data& (qui peut être casté en const Data&). 
 +  for (Data &: v
 +  
 +    std::cout << i.getA() << std::endl; 
 +  } 
 +  // Utilisation de begin et end en const. 
 +  // Le type de retour est obligatoirement const Data&
 +  for (const Data &i : static_cast<const DataSample>(v)) 
 +  { 
 +    std::cout << i.getA() << std::endl; 
 +  } 
 +}
 </code> </code>
  
-Utiliser de préférence la version ''for each'' pour parcourir l'ensemble d'un conteneur.+====Ranges====
  
-  * Conteneur ne supportant pas les index :+Les ''ranges'' de la ''std'' n'implémentent que des algorithmes en $O(1)$. Il n'est donc pas possible de trier des vues. 
 + 
 +  * Boucle
  
 <code cpp> <code cpp>
-std::set<intset { 10, 20, 30, 40 }; +#include <ranges>
-std::set<int>::const_iterator it;+
  
-for (it = set.begin(); it != set.end(); it+++for (int i : std::views::iota(0, 100)) 
-  std::cout << *it << std::endl;+  std::cout << << std::endl;
 </code> </code>
  
-Utiliser de préférence la version ''for each'' pour parcourir l'ensemble d'un conteneur.+  * Pour faire la boucle à l'envers :
  
-===for each===+<code cpp> 
 +#include <ranges>
  
-  Conteneur de type primitif :+for (int i : std::views::iota(0, 100) | std::views::reverse) 
 +  std::cout << i << std::endl; 
 + 
 +</code> 
 + 
 +  S'arrêter sous une certaine condition :
  
 <code cpp> <code cpp>
-std::array<int, 4arr = { 10, 20, 30, 40 }; +#include <ranges> 
-for (int i : arr)+ 
 +for (int i : std::views::iota(0, 100) | std::views::take_while([](int i){ return 0 <= i && i <= 15; }))
   std::cout << i << std::endl;   std::cout << i << std::endl;
 </code> </code>
  
-  * Conteneur de type non primitif :+  * Filter les valeurs :
  
 <code cpp> <code cpp>
-std::set<std::stringset { "10", "20", "30", "40" };+#include <ranges>
  
-for (const std::string& val set+for (int i : std::views::iota(0, 100) | std::views::filter([](int i){ return 50 <= i && i <= 66; })
-  std::cout << val << std::endl;+  std::cout << << std::endl;
 </code> </code>
  
-  * Conteneur multi-types (''std::map'', ''std::tuple'', ...) :+  * Modifier les valeurs dans la vue :
  
 <code cpp> <code cpp>
-std::map<int, std::stringmap { {10, "10"}, {20, "20"}, {30, "30"}, {40, "40"} };+#include <ranges>
  
-// L'utilisation de auto est obligatoire. +int main() { 
-for (const auto [keyvalue] map+  for (const std::stringi : 
-  std::cout << value << std::endl;+      // Integer 
 +      std::views::iota(0100) | 
 +      // const char * 
 +      std::views::transform([](int i{ 
 +        if (i % 15 == 0) 
 +          return "FooBar\n"; 
 +        else if (i % 3 == 0) 
 +          return "Foo\n"; 
 +        else if (i % 5 == 0) 
 +          return "Bar\n"; 
 +        else 
 +          return ""; 
 +      })) 
 +    std::cout << << std::endl; 
 +}
 </code> </code>
  
-  * Sur une classe personnalisée :+<WRAP center round important 60%> 
 +Les vues sont en lecture seule 
 +</WRAP>
  
-Il faut définir l'itérateur et la classe à parcourir. [[https://www.cprogramming.com/c++11/c++11-ranged-for-loop.html|C++11 range-based for loops]] {{ :lang:cpp:boucles:range-based_for_loops_in_c_11_-_cprogramming.com_2019-12-26_12_35_03_.html |Archive le 26/12/2019}}+Le code  
 +<code cpp> 
 +int main() { 
 +  std::vector<int> v {1, 2, 3, 4, 5, 6, 7, 8, 9}; 
 +  for (int & i : 
 +       | 
 +       std::views::take(5)) 
 +    i = 3; 
 +  for (const int & i v) 
 +    std::cout << i << "\n"; 
 +
 +</code>
  
-L'exemple ci-dessous se passe de ''template''.+affichera
  
-Il faut commencer par déclarer l'itérateur.+<code> 
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +</code> 
 + 
 +  * Ne prendre que les premiers résultats
  
 <code cpp> <code cpp>
 +#include <ranges>
  
 +int main() {
 +  for (int i :
 +       std::views::iota(0, 100) |
 +       std::views::take(10))
 +    std::cout << i << std::endl;
 +}
 </code> </code>
 +
 +=====Via une coroutine=====
 +
 +<code cpp>
 +#include <experimental/generator>
 +#include <iostream>
 + 
 +std::experimental::generator<int> loop(int iterations)
 +{
 +  for (int i = 0; i < iterations; i++)
 +  {
 +    co_yield i;
 +  }
 +}
 + 
 +int main()
 +{
 +  for (int i : loop(100))
 +  {
 +    std::cout << i << std::endl;
 +  }
 +}
 +</code>
 +
lang/cpp/boucles.1577364989.txt.gz · Dernière modification : 2019/12/26 13:56 de root