Outils d'utilisateurs

Outils du Site


predicats

Différences

Cette page vous donne les différences entre la révision choisie et la version actuelle de la page.

Lien vers cette vue

predicats [2014/08/30 13:13]
gbdivers
predicats [2019/02/21 23:04] (Version actuelle)
alavida Corps de la fonction lambda est entre les accolades et non entre les crochets
Ligne 1: Ligne 1:
  
-^ Chapitre précédent ^ [[programmez_avec_le_langage_c|Sommaire principal]] ^ Chapitre suivant ^+[[autres_collections|Chapitre précédent]] ^ [[programmez_avec_le_langage_c|Sommaire principal]] ^ [[bitset|Chapitre suivant]] ^
  
-====== Les foncteurs ======+ 
 +====== Les foncteurs et fonctions lambdas ======
  
 __foncteur ? fonction objet ? opérateur ? autre ? __ __foncteur ? fonction objet ? opérateur ? autre ? __
Ligne 20: Ligne 21:
 Cet algorithme est dit "modifiant" puisqu'il modifie directement le conteneur sur lequel on applique la fonction. Cet algorithme est dit "modifiant" puisqu'il modifie directement le conteneur sur lequel on applique la fonction.
  
-Fondamentalement, cet algorithme fonctionne de la façon suivante : il parcourir les éléments de la collection et réalise des tests de comparaison par paire d'éléments. Pour faire cette comparaison, l'algorithme utilise l'opérateur de comparaison ''<'' sur les éléments. Par exemple, pour faire le trie d'un tableau d'entiers (''vector<int>''), l'algorithme réaliser des comparaisons d'entiers (''valeur 1 < valeur 2'').+Fondamentalement, cet algorithme fonctionne de la façon suivante : il parcourt les éléments de la collection et réalise des tests de comparaison par paire d'éléments. Pour faire cette comparaison, l'algorithme utilise l'opérateur de comparaison ''<'' sur les éléments. Par exemple, pour faire le tri d'un tableau d'entiers (''vector<int>''), l'algorithme réalise des comparaisons d'entiers (''valeur 1 < valeur 2'').
  
-Dit autrement, cela veut dire que si on utilise un ''vector<un_type>'', il faut que la comparaison ''<'' est un sens pour ce type ''un-type'' (ce qui sera le cas avec la majorité des types de base du C++).+Dit autrement, cela veut dire que si on utilise un ''vector<un_type>'', il faut que la comparaison ''<'' ait un sens pour ce type ''un_type'' (ce qui sera le cas avec la majorité des types de base du C++).
  
 On dit que l'opérateur ''<'' est le prédicat utilisé par l'algorithme de trie ''std::sort''. Plus généralement, un prédicat est une expression qui retourne un booléen (''true'' ou ''false''). Les différents algorithmes de la bibliothèque standard n'utilisent pas tous l'opérateur ''<'', certains utilisent l'opérateur d'égalité ''=='', d'autres n'utilisent pas de prédicat. On dit que l'opérateur ''<'' est le prédicat utilisé par l'algorithme de trie ''std::sort''. Plus généralement, un prédicat est une expression qui retourne un booléen (''true'' ou ''false''). Les différents algorithmes de la bibliothèque standard n'utilisent pas tous l'opérateur ''<'', certains utilisent l'opérateur d'égalité ''=='', d'autres n'utilisent pas de prédicat.
  
-Imaginons maintenant que l'on souhaite trier une collection dans l'ordre inverse, c'est-à-dire du plus grand au plus petit. Une première solution serait de trier dans l'ordre par défaut (plus petit au plus grand), puis d'inverser l'ordre des éléments. Une autre solution serait de réécrire un algorithme de trie (appelé ''reverse_sort'' par exemple) et qui trie dans l'ordre inverse (du plus grand au plus petit).+Imaginons maintenant que l'on souhaite trier une collection dans l'ordre inverse, c'est-à-dire du plus grand au plus petit. Une première solution serait de trier dans l'ordre par défaut (plus petit au plus grand), puis d'inverser l'ordre des éléments. Une autre solution serait de réécrire un algorithme de tri (appelé ''reverse_sort'' par exemple) et qui trie dans l'ordre inverse (du plus grand au plus petit).
  
-Ces deux solutions ne sont pas correctes en termes de C++ moderne. La première est inutilement plus compliqué (il faut écrire deux lignes au lieu d'une seule), la seconde demande de réécrire l'algorithme de trie.+Ces deux solutions ne sont pas correctes en termes de C++ moderne. La première est inutilement plus compliqué (il faut écrire deux lignes au lieu d'une seule), la seconde demande de réécrire l'algorithme de tri.
  
 ===== Les foncteurs de la bibliothèque standard ===== ===== Les foncteurs de la bibliothèque standard =====
Ligne 78: Ligne 79:
 Le prédicat ''greater'' est une classe template, il faut préciser le type que l'on souhaite comparer comme argument template (donc entre chevrons). Les parenthèses permettent d'instancier un objet à partir de la classe ''greater''. Vous n'avez pas encore vu les classes, vous verrez cela en détail dans la partie sur la programmation objet. Pour le moment, le plus important est de se souvenir de la syntaxe. Le prédicat ''greater'' est une classe template, il faut préciser le type que l'on souhaite comparer comme argument template (donc entre chevrons). Les parenthèses permettent d'instancier un objet à partir de la classe ''greater''. Vous n'avez pas encore vu les classes, vous verrez cela en détail dans la partie sur la programmation objet. Pour le moment, le plus important est de se souvenir de la syntaxe.
  
-Vous pouvez consulter la liste des différents foncteurs de la bibliothèque standard dans la page de documentation [[http://en.cppreference.com/w/cpp/utility/functional|Function objects]].+Il est possible d'utiliser les foncteurs directement, sans passer par un algorithmePour cela, il faut créer un objet du type ''std::greater'', puis l'appeler comme une fonction (d'où leur nom : foncteur = "function object") :
  
-Les prédicats sont les suivants :+<code cpp main.cpp> 
 +#include <iostream> 
 +#include <functional>
  
-  * Comparaisons +int main() { 
-    * ''equal_to'' pour tester l'égalité ''=='' ; +    std::greater<intgreater_operator {}
-    * ''not_equal_to'' pour tester la différence ''!='' ; +    std::cout << std::boolalpha
-    * ''greater'' pour la comparaison ''>'' +    std::cout &lt;<greater_operator(1, 2) << std::endl; 
-    * ''less'' pour tester l'égalité ''<'' +    std::cout &lt;&lt; greater_operator(3, 2) << std::endl
-    * ''greater_equal'' pour tester l'égalité ''&gt;='' ; +} 
-    * ''less_equal'' pour tester l'égalité ''<=''. +</code>
-  * Opérations logiques +
-    * ''logical_and'' pour AND &amp;&amp+
-    * ''logical_or'' OR ||  +
-    * ''logical_not'' Not !x+
  
-__ bind ? __+Pour bien comprendre la différence entre les divers types de fonction, revoyons les multiples syntaxes pour créer une variable (nommée ''object'') d'un type donné (''MyObject'') et sur laquelle nous appliquons une fonction : 
 + 
 +<code cpp> 
 +MyObject object {}; 
 + 
 +foo(object);  // fonction libre 
 +object.foo(); // fonction membre 
 +object();     // foncteur 
 +</code> 
 + 
 +Pour le moment, vous avez seulement vu comment utiliser ces types de fonction. Vous verrez dans les chapitres sur les fonctions et sur la programmation objet comment les créer. En pratique, il vous suffit de lire la documentation pour savoir quelle est la syntaxe correcte d'une fonction (sa signature, ses paramètres, savoir si c'est une fonction libre ou membre, etc.) Avec l'expérience, vous vous souviendrez des fonctions les plus utilisées et vous n'aurez plus besoin de lire la documentation pour vérifier la syntaxe. Un éditeur de code avec l'auto-complétion (qui affiche la signature des fonctions) peut également être très utile pour gagner du temps. 
 + 
 +Vous pouvez consulter la liste des différents foncteurs de la bibliothèque standard dans la page de documentation [[http://en.cppreference.com/w/cpp/utility/functional|Function objects]]. Vous voyez dans cette page que les foncteurs sont rangés en plusieurs catégories : 
 + 
 +  * les opérations arithmétiques (//arithmetic operations//) : ''plus'', ''minus'', ''multiplies'', ''divides'', ''modulus'' et ''negate'' ; 
 +  * les comparaisons (//comparisons//) : ''equal_to'', ''not_equal_to'', ''greater'', ''less'', ''greater_equal'' et ''less_equal'' ; 
 +  * les opérations logiques (//Logical operations//) : ''logical_and'', ''logical_or'' et ''logical_not'' ; 
 +  * les opérations sur les bits (//Bitwise operations//) : ''bit_and'', ''bit_or'', ''bit_xor'' et ''bit_not''. 
 + 
 +__ composition de fonction, not1, not2, bind ? __ 
 + 
 +Plus généralement, il est possible d'utiliser n'importe quelle fonction de la bibliothèque standard, à partir du moment où celle-ci respecte la signature attendue par un algorithme donné. En particulier, il est possible d'utiliser les fonctions de manipulations de caractères, définies dans le fichier d'en-tête ''<cctype>'' : [[http://en.cppreference.com/w/cpp/string/byte|Null-terminated byte strings]] (ou leur équivalent pour ''wstring'' : [[http://en.cppreference.com/w/cpp/string/wide|Null-terminated wide strings]]). Ces fonctions se divisent en deux catégories :  
 + 
 +  * les fonctions de test (//Character classification//) :  
 +    * ''isalnum'' (alphanumérique) ; 
 +    * ''isalpha'' (alphabétique) ; 
 +    * ''islower'' (minuscule) ; 
 +    * ''isupper'' (majuscule) ; 
 +    * ''isdigit'' (chiffre décimal) ; 
 +    * ''isxdigit'' (chiffre hexadécimal) ; 
 +    * ''iscntrl'' (caractère de contrôle) ; 
 +    * ''isgraph'' (caractère graphique) ; 
 +    * ''isspace'' (espace) ; 
 +    * ''isblank'' (caractère blanc) ; 
 +    * ''isprint'' (caractère affichable) ; 
 +    * ''ispunct'' (ponctuation). 
 +  * les fonctions de modification (//Character manipulation//) : 
 +    * ''tolower'' (convertie en minuscule) ; 
 +    * ''toupper'' (converti en majuscule). 
 + 
 +La syntaxe pour utiliser les fonctions dans un algorithme est différente de celle pour les objets-fonctions. Il faut simplement mettre la nom de la fonction. Par exemple, pour convertir une chaîne de caractères en majuscule, il est possible d'utiliser l'algorithme ''transform'' (que vous verrez par la suite) et la fonction ''toupper'' : 
 + 
 +<code cpp main.cpp> 
 +#include <iostream> 
 +#include <string> 
 +#include <algorithm> 
 + 
 +int main() { 
 +    std::string s { "abcdef" }; 
 +    std::transform(begin(s), end(s), begin(s), toupper); 
 +    std::cout << s << std::endl; 
 +
 +</code> 
 + 
 +affiche : 
 + 
 +<code> 
 +ABCDEF 
 +</code>
  
 ==== Exercices ==== ==== Exercices ====
  
-  * tirer avec d'autres prédicats+  * trier avec d'autres prédicats
   * combiner des prédicats   * combiner des prédicats
  
Ligne 107: Ligne 164:
 Il est important que vous sachiez créer des fonctions, c'est un point fondamental en C++, vous les utiliserez dans tous vos codes. Et plus important, ce qui sera fondamental est de savoir découper correctement les problèmes complexes en fonctions plus simples. Ce chapitre ne sera pas suffisant pour étudier toutes les possibilités offertes par les fonctions, nous reviendrons dessus en détail par la suite. Cette partie se focalise sur l'utilisation simple des fonctions lambdas avec les algorithmes de la bibliothèque standard. Il est important que vous sachiez créer des fonctions, c'est un point fondamental en C++, vous les utiliserez dans tous vos codes. Et plus important, ce qui sera fondamental est de savoir découper correctement les problèmes complexes en fonctions plus simples. Ce chapitre ne sera pas suffisant pour étudier toutes les possibilités offertes par les fonctions, nous reviendrons dessus en détail par la suite. Cette partie se focalise sur l'utilisation simple des fonctions lambdas avec les algorithmes de la bibliothèque standard.
  
-Les fonctions lambdas sont une technique issue de la programmation fonctionnelle. Vous avez déjà utiliser des fonctions (membres ou libres) et vous avez déjà définit une fonction : la fonction ''main''. Pour rappel, une fonction permet de réaliser une tâche particulière et est constituée de :+Les fonctions lambdas sont une technique issue de la programmation fonctionnelle. Vous avez déjà utilisé des fonctions (membres ou libres) et vous avez déjà défini une fonction : la fonction ''main''. Pour rappel, une fonction permet de réaliser une tâche particulière et est constituée de :
  
   * un nom de fonction (''main'') ;   * un nom de fonction (''main'') ;
Ligne 129: Ligne 186:
 <note info>''Programmation fonctionnelle''</note> <note info>''Programmation fonctionnelle''</note>
  
-Une fonction lambda est une fonction particulière. Elle n'a pas de nom et peut être déclarée dans le corps d'une autre fonction. A part cela, elle se comporte comme une fonction classique et peut recevoir des arguments, retourner une valeur. Il existe plusieurs façon d'écrire des fonctions lambdas, mais comme nous les utilisons ici dans les algorithmes de la bibliothèques standard, il est nécessaire de respecter la signature imposée par les algorithmes.+Une fonction lambda est une fonction particulière. Elle n'a pas de nom (elle est dite anonyme) et peut être déclarée dans le corps d'une autre fonction. A part cela, elle se comporte comme une fonction classique et peut recevoir des arguments, retourner une valeur. Il existe plusieurs façon d'écrire des fonctions lambdas, mais comme nous les utilisons ici dans les algorithmes de la bibliothèques standard, il est nécessaire de respecter la signature imposée par les algorithmes.
  
 La définition d'une fonction lambda se décompose en trois parties : La définition d'une fonction lambda se décompose en trois parties :
Ligne 161: Ligne 218:
 </code> </code>
  
-Le corps de la fonction lambda (entre les crochets) peut contenir plusieurs lignes (séparées par un point-virgule), déclarer des variables, appeler d'autres fonctions, etc. Bref, vous pouvez mettre dans le corps d'une fonction lambda toutes les instructions que vous souhaitez.+Le corps de la fonction lambda (entre les accolades) peut contenir plusieurs lignes (séparées par un point-virgule), déclarer des variables, appeler d'autres fonctions, etc. Bref, vous pouvez mettre dans le corps d'une fonction lambda toutes les instructions que vous souhaitez.
  
 Pour écrire une fonction lambda qui prend deux paramètres, compare les valeurs et retourne un booléen, on peut donc écrire : Pour écrire une fonction lambda qui prend deux paramètres, compare les valeurs et retourne un booléen, on peut donc écrire :
Ligne 220: Ligne 277:
   * trier selon la valeur absolue   * trier selon la valeur absolue
  
-^ Chapitre précédent ^ [[programmez_avec_le_langage_c|Sommaire principal]] ^ Chapitre suivant ^ 
  
-{{tag> Cours C++}}+^ [[autres_collections|Chapitre précédent]] ^ [[programmez_avec_le_langage_c|Sommaire principal]] ^ [[bitset|Chapitre suivant]] ^ 
predicats.1409397206.txt.gz · Dernière modification: 2014/08/30 13:13 par gbdivers