Cette page vous donne les différences entre la révision choisie et la version actuelle de la page.
comparer_strings [2014/09/04 00:08] gbdivers |
— (Version actuelle) | ||
---|---|---|---|
Ligne 1: | Ligne 1: | ||
- | ^ Chapitre précédent ^ [[programmez_avec_le_langage_c|Sommaire principal]] ^ Chapitre suivant ^ | ||
- | |||
- | ====== Tester l'égalité ====== | ||
- | |||
- | Pour comparer si deux "choses" sont égales, le plus simple sera généralement d'utiliser l'opérateur de comparaison ''=='' que vous avez déjà vu. Cet opérateur fonctionne aussi bien pour les types fondamentaux du C++ (//build-in types//, comme ''int'', ''float'', etc.) que pour certains types de classe (les classes à sémantique de valeur). Il est également possible d'utiliser des algorithmes dans les cas d'utilisation plus spécifiques. | ||
- | |||
- | ===== L'opérateurs de comparaison ===== | ||
- | |||
- | Dans les chapitres précédents, vous avez vu l'utilisation de l'opérateur de comparaison ''=='' (//egal-to operator//). Les collections de la bibliothèque standard, comme ''vector'', ''array'' ou ''string'', fournissent également cet opérateur. Vous pouvez donc écrire : | ||
- | |||
- | <code cpp main.cpp> | ||
- | #include <iostream> | ||
- | #include <string> | ||
- | |||
- | int main() { | ||
- | std::string const s1 { "salut" }; | ||
- | std::string const s2 { "salut" }; | ||
- | std::string const s3 { "hello" }; | ||
- | std::cout << std::boolalpha; | ||
- | std::cout << (s1 == s2) << std::endl; | ||
- | std::cout << (s1 == s3) << std::endl; | ||
- | } | ||
- | </code> | ||
- | |||
- | affiche : | ||
- | |||
- | <code> | ||
- | true | ||
- | false | ||
- | </code> | ||
- | |||
- | Remarque : ne pas oublier les parenthèses autour du test d'égalité pour ''string''. L'opérateur ''<<'' ayant un sens pour cette classe, le compilateur ne pourra pas savoir si vous souhaitez écrire : | ||
- | |||
- | <code cpp> | ||
- | std::cout << (s1 == s2) << std::endl; | ||
- | std::cout << s1 == (s2 << std::endl); | ||
- | </code> | ||
- | |||
- | De même pour les collections : | ||
- | |||
- | <code cpp main.cpp> | ||
- | #include <iostream> | ||
- | #include <vector> | ||
- | |||
- | int main() { | ||
- | std::vector<int> const v1 { 1, 2, 3, 4 }; | ||
- | std::vector<int> const v2 { 1, 2, 3, 4 }; | ||
- | std::vector<int> const v3 { 4, 3, 2, 1 }; | ||
- | std::cout << std::boolalpha; | ||
- | std::cout << (v1 == v2) << std::endl; | ||
- | std::cout << (v1 == v3) << std::endl; | ||
- | } | ||
- | </code> | ||
- | |||
- | affiche : | ||
- | |||
- | <code> | ||
- | true | ||
- | false | ||
- | </code> | ||
- | |||
- | Avec les collections, l'opérateur d'égalité compare les éléments de la collection un par un et s'il trouve une différence, il retourne ''false''. S'il arrive à la fin de la collection sans trouver de différence, il retourne ''true''. | ||
- | |||
- | Pour vérifier si deux chaînes sont différentes, il est possible d'utiliser l'opérateur booléen de négation ''!'' : ''!(s1 == s2)''. Plus simplement, on peut directement utiliser l'opérateur de comparaison ''!='' (//not-equal-to operator//). | ||
- | |||
- | <code cpp main.cpp> | ||
- | #include <iostream> | ||
- | #include <string> | ||
- | |||
- | int main() { | ||
- | std::string const s1 { "salut" }; | ||
- | std::string const s2 { "salut" }; | ||
- | std::string const s3 { "hello" }; | ||
- | std::cout << std::boolalpha << (s1 != s2) << std::endl; | ||
- | std::cout << (s1 != s3) << std::endl; | ||
- | } | ||
- | </code> | ||
- | |||
- | affiche : | ||
- | |||
- | <code> | ||
- | false | ||
- | true | ||
- | </code> | ||
- | |||
- | On voit ici que les opérateurs ''=='' et ''!='' sont étroitement liés. Lorsque l'un de ces deux opérateurs est utilisable, on peut s'attendre à ce que l'autre opérateur le soit également. On dit qu'une classe qui propose l'opérateur d'égalité ''=='' qu'elle respecte le concept de "comparable par égalité" ([[http://en.cppreference.com/w/cpp/concept/EqualityComparable|EqualityComparable]]). Ce concept précise que l'opérateur d'égalité doit suivre les propriétés suivantes : | ||
- | |||
- | * réflexivité : quelque soit ''a'', ''a == a'' est toujours vrai ; | ||
- | * commutativité : si ''a == b'', alors ''b == a'' ; | ||
- | * transitivité : si ''a == b'' et ''b == c'', alors ''a == c''. | ||
- | |||
- | Ce concept est assez classique, on le retrouve en mathématique dans la théorie des ensembles. On voit ici un point important : lorsqu'une classe définit un opérateur ''=='', on s'attend à ce qu'elle suive un certain nombre de règles. On dit qu'elle suis une sémantique, cela facilite son utilisation. Du point de vue de l'utilisateur de cette classe, on pourra utiliser n'importe quelle classe respectant cette sémantique de la même façon. Du point de vue du concepteur de la classe (ce que vous apprendrez à faire dans la suite de ce cours), il suffit de définir les sémantiques que l'on souhaite donner à notre classe, l'écriture de la classe en découlera. | ||
- | |||
- | Au contraire, le non respect d'une sémantique sera très perturbant pour l'utilisateur - et une source d'erreur sans fin. Imaginez que l'opérateur ''=='' ne réalise pas un test d'égalité, mais permet de faire la concaténation de deux chaînes ? | ||
- | |||
- | Bien sûr, ces considérations s'appliquent à l'ensemble des sémantiques usuelles, en particulier celle que l'on connait en mathématique (addition avec ''+'', soustraction avec ''-'', etc.) | ||
- | |||
- | ===== La sémantique de valeur ===== | ||
- | |||
- | Un concept complexe peut être décomposé en une série de concepts plus simple (par exemple "est comparable par égalité" est composé des concepts "est réflexif", "est commutatif" et "est transitif" que l'on a vu avant). De la même façon, il est possible de combiner des concepts pour créer de nouveaux concepts plus complexe. Un concept peut également autorisé ou interdire l'utilisation d'autres concepts (par exemple, le concept "est égal" autorise l'utilisation du concept "est différent"). | ||
- | |||
- | C'est la cas du concept "est comparable par égalité", qui fait parti d'un concept plus général : la sémantique de valeur. Cette sémantique s'applique à tout ce qui représente une valeur : un entier, un nombre réel, un nombre complexe, une chaîne de caractères, un tableau de données, etc. La sémantique de valeur autorise les concepts suivants : | ||
- | |||
- | **Constructible** par défaut ([[http://en.cppreference.com/w/cpp/concept/DefaultConstructible|DefaultConstructible]]). On peut initialiser avec une valeur par défaut (on parle aussi de "zero initialization" puisque la valeur par défaut sera 0 ou équivalent). | ||
- | |||
- | <code cpp> | ||
- | int const i {}; // construction par défaut | ||
- | </code> | ||
- | |||
- | **Copiable** par construction ([[http://en.cppreference.com/w/cpp/concept/CopyConstructible|CopyConstructible]]) et par affectation ([[http://en.cppreference.com/w/cpp/concept/CopyAssignable|CopyAssignable]]). Cela signifie que l'on peut créer une valeur en copiant une autre valeur. Par exemple, pour un entier : | ||
- | |||
- | <code cpp> | ||
- | int const i { 123 }; | ||
- | int j { i }; // construction par copie | ||
- | j = i; // affectation par copie | ||
- | </code> | ||
- | |||
- | **Comparable** par égalité ([[http://en.cppreference.com/w/cpp/concept/DefaultConstructible|EqualityComparable]]) ou par "plus petit que" ([[http://en.cppreference.com/w/cpp/concept/LessThanComparable|LessThanComparable]]). Cela signifie que l'on peut utiliser les opérateurs d'égalité ''=='' et "plut petit que" ''<'' (ainsi que les opérateurs dérivés : "différent de" ''!='', "plus petit ou égal à" <html><=</html>, "plus grand que" ''>'' et "plus grand ou égal à" <html>>=</html>) : | ||
- | |||
- | <code cpp> | ||
- | int const i { 123 }; | ||
- | int const j { 456 }; | ||
- | cout << (i == j) << endl; // égalité | ||
- | cout << (i != j) << endl; // différent | ||
- | cout << (i < j) << endl; // plus petit | ||
- | cout << (i <= j) << endl; // plus petit ou égal | ||
- | cout << (i > j) << endl; // plus grand | ||
- | cout << (i >= j) << endl; // plus grand ou égal | ||
- | </code> | ||
- | |||
- | Si cela a un sens, la sémantique de valeur permet également de définir des opérateurs arithmétiques classiques : addition ''+'', soustraction ''-'', multiplication ''*'' et division ''/''. Par exemple, pour les entiers : | ||
- | |||
- | <code cpp> | ||
- | int const i { 123 }; | ||
- | int const j { 456 }; | ||
- | cout << (i + j) << endl; // addition | ||
- | cout << (i - j) << endl; // soustraction | ||
- | cout << (i * j) << endl; // multiplication | ||
- | cout << (i / j) << endl; // division | ||
- | </code> | ||
- | |||
- | Le rôle de ces opérateurs peut varier en fonction du type. Par exemple, l'opérateur ''+'' correspondra à une addition pour les types numériques et à une concaténation pour les chaînes de caractères ''string''. | ||
- | |||
- | <code cpp main.cpp> | ||
- | #include <iostream> | ||
- | #include <string> | ||
- | |||
- | int main() { | ||
- | int const i1 { 1 }; | ||
- | int const i2 { 2 }; | ||
- | std::cout << (i1 + i2) << std::endl; // addition | ||
- | std::string const s1 { "1" }; | ||
- | std::string const s2 { "2" }; | ||
- | std::cout << (s1 + s2) << std::endl; // concaténation | ||
- | } | ||
- | </code> | ||
- | |||
- | affiche : | ||
- | |||
- | <code> | ||
- | 3 | ||
- | 12 | ||
- | </code> | ||
- | |||
- | De plus, selon les types, tous les opérateurs n'ont pas forcement un sens. Par exemple, pour les chaînes ''string'', seul l'opérateur ''+'' a un sens, les autres opérateurs ne sont pas définis. Pour les collections (''vector'', ''array'', etc.), l'opérateur ''+'' n'est pas défini (c'est un choix des concepteurs, ils auraient pu définir l'opérateur ''+'' pour fussionner deux collections, mais pour des raisons de sémantique, ce n'est pas le cas). | ||
- | |||
- | <note info>Les deux grands types de classes sont les classes à sémantique de valeur (que vous avez vu dans ce chapitre) et les classes à sémantique d'entité. Vous apprendrez dans la partie "programmation orientée objet" comment créer ces types de classes. Pour les distinguer, le plus simple est de se poser des questions sur ce que peut faire une classe ou non. | ||
- | |||
- | * Est-ce que cela à un sens de pouvoir copier un objet ? | ||
- | * Est-ce que cela à un sens de tester si deux objets sont égaux ? | ||
- | * Est-ce que cela à un sens d’additionner deux objets ? | ||
- | |||
- | La majorité des classes de la bibliothèque standard sont à sémantique de valeur. Vous verrez dans la partie sur la programmation objet comment identifier et créer des classes à sémantique d'entité.</note> | ||
- | |||
- | ===== Les algorithmes d'égalité ===== | ||
- | |||
- | Si vous souhaitez comparer deux sous-ensembles de collections ou si vous souhaitez utiliser un prédicat différent, il ne sera pas possible d'utiliser l'opérateur d'égalité ''==''. Dans ce cas, la bibliothèque standard fournit l'algorithme ''std::equal'' pour comparer si deux collections sont identiques ou non. | ||
- | |||
- | Lorsque l'on découvre une nouvelle fonction, la première chose à faire est de jetter un coup d'oeil sur la documentation : [[http://en.cppreference.com/w/cpp/algorithm/equa|std::equal]]. Cette page nous apprend plusieurs choses : | ||
- | |||
- | * cet algorithme est défini dans le fichier d'en-tête ''<algorithm>'', il faudra donc l'inclure dans votre code pour utiliser ''equal'' ; | ||
- | * il existe quatre versions de cet algorithme : | ||
- | * le premier prend en argument le début et la fin d'une première collection et le début d'une seconde collection ; | ||
- | * le second est similaire au premier, avec un prédicat personnalisé ; | ||
- | * la troisième prend en argument le début et la fin de la première collection, puis de la seconde ; | ||
- | * le quatrième est similaire au troisième, avec un prédicat personnalisé. | ||
- | * le prédicat doit respecter la signature suivante : ''bool pred(const Type1 &a, const Type2 &b);'' (c'est donc une fonction binaire - une fonction qui prend deux arguments - et retourne un booléen). | ||
- | |||
- | La page de documentation donne également des codes d'exemple d'utilisation de ces fonctions. | ||
- | |||
- | La première (et deuxième) version de ''equal'' doit être utilisé avec précaution. Si on compare par exemple deux collections de tailles différentes (par exemple les chaînes ''"abcd"'' et ''"abcdEF"''), la comparaison se terminera lorsque l'algorithme atteint la fin de la première collection donnée en argument. Dans ce cas, les deux chaînes seront considérées comme égale, alors que ce sont simplement les premiers caractères de la première chaîne qui sont retrouvé dans la seconde. | ||
- | |||
- | La troisième (et quatrième) version de ''equal'' permet de tester si l'algorithme est arrivé à la fin des deux collections et donc qu'elle sont parfaitement identiques. Voici un code d'exemple pour illustrer ce point : | ||
- | |||
- | <code cpp> | ||
- | #include <iostream> | ||
- | #include <string> | ||
- | #include <algorithm> | ||
- | |||
- | int main() { | ||
- | std::string const s1 { "abcd" }; | ||
- | std::string const s2 { "abcdEF" }; | ||
- | std::cout << std::boolalpha; | ||
- | std::cout << std::equal(begin(s1), end(s1), begin(s2)) << std::endl; | ||
- | std::cout << std::equal(begin(s2), end(s2), begin(s1)) << std::endl; | ||
- | std::cout << std::endl; | ||
- | std::cout << std::equal(begin(s1), end(s1), begin(s2), end(s2)) << std::endl; | ||
- | std::cout << std::equal(begin(s2), end(s2), begin(s1), end(s1)) << std::endl; | ||
- | } | ||
- | </code> | ||
- | |||
- | affiche : | ||
- | |||
- | <code> | ||
- | true | ||
- | false | ||
- | |||
- | false | ||
- | false | ||
- | </code> | ||
- | |||
- | Par défaut, préférez l'utilisation de la version prenant le début et la fin des deux collections (les versions 3 et 4 de ''std::equal''). | ||
- | |||
- | <note warning> | ||
- | Attention aux éléments que vous passez en argument dans les fonctions. Le compilateur vérifie que vous passer des collections de types identiques en argument, pas que les informations passées ont un sens. Par exemple, si vous passer en argument un élément d'une collection puis un élément d'une seconde collection, cela n'a pas de sens de parcourir une collection entre ce deux éléments. | ||
- | |||
- | <code cpp> | ||
- | std::equal(begin(s1), end(s2), begin(s2)); // erreur, les deux premiers arguments | ||
- | // ne proviennent pas de la même collection | ||
- | </code> | ||
- | |||
- | Dans ce cas, ce code ne produit pas d'erreur de compilation, mais un comportement indéterminé (//undefined behavior//, UB). Ce type d'erreur est assez complexe à détecter et à corriger, il faut être très attentif pour les éviter. | ||
- | </note> | ||
- | |||
- | ==== Comparer des collections différentes ==== | ||
- | |||
- | Comme cela a été dit auparavant, la classe ''string'' peut être vu comme une collection de caractères (''char''). Cependant, si on essaie de comparer une variable de type ''string'' à une tableau de caractères, on obtient une erreur : | ||
- | |||
- | <code cpp main.cpp> | ||
- | #include <iostream> | ||
- | #include <string> | ||
- | #include <vector> | ||
- | #include <algorithm> | ||
- | |||
- | int main() { | ||
- | std::string const s { "abcdef" }; | ||
- | std::vector<char> const a { 'a', 'b', 'c', 'd', 'e', 'f' }; | ||
- | std::cout << std::boolalpha; | ||
- | std::cout << (s == a) << std::endl; | ||
- | } | ||
- | </code> | ||
- | |||
- | affiche l'erreur à la compilation suivante : | ||
- | |||
- | <code> | ||
- | main.cpp:10:21: error: invalid operands to binary expression ('const std::string' | ||
- | (aka 'const basic_string<char, char_traits<char>, allocator<char> >') and | ||
- | 'const std::vector<char>') | ||
- | std::cout << (s == a) << std::endl; | ||
- | ~ ^ ~ | ||
- | 1 error generated. | ||
- | </code> | ||
- | |||
- | Cette erreur signifie que le compilateur ne trouve pas d'opérateur d'égalité ''=='' permettant de comparer un type ''string'' avec un type ''vector<char>''. En effet, les opérateurs de comparaison sont définis pour accepter deux arguments de même type, par exemple deux ''string'' ou deux ''vector<char>'', mais pas deux collection de type différents, même si ces deux types correspondent tous deux à des collections de ''char'' (on parle parfois de typage "fort" du C++). | ||
- | |||
- | Dans cette situation, il est possible d'utiliser la fonction ''equal'' pour tester l'égalité de deux collections. Cet algorithme fonctionne sur des collections de types différents, à partir du moment où les éléments sont comparable par égalité. Par exemple, il sera possible de comparer des ''string'' et des ''vector<char>'' (les éléments sont dans les deux cas des ''char'') ou des ''vector<int>'' et ''vector<float>'' (il est possible de comparer un entier et un nombre réel), mais pas ''vector<int>'' et ''vector<string>'' (''int'' et ''string'' ne sont pas comparable par égalité). | ||
- | |||
- | En utilisant ''std::equal'', la comparaison devient : | ||
- | |||
- | <code cpp main.cpp> | ||
- | #include <iostream> | ||
- | #include <string> | ||
- | #include <vector> | ||
- | #include <algorithm> | ||
- | |||
- | int main() { | ||
- | std::string const s { "abcdef" }; | ||
- | std::vector<char> const v1 { 'a', 'b', 'c', 'd', 'e', 'f' }; | ||
- | std::vector<char> const v2 { 'a', 'z', 'e', 'r', 't', 'y' }; | ||
- | std::cout << std::boolalpha; | ||
- | std::cout << std::equal(begin(s), end(s), begin(v1), end(v1)) << std::endl; | ||
- | std::cout << std::equal(begin(s), end(s), begin(v2), end(v2)) << std::endl; | ||
- | } | ||
- | </code> | ||
- | |||
- | affiche : | ||
- | |||
- | <code> | ||
- | true | ||
- | false | ||
- | </code> | ||
- | |||
- | ==== Comparer des parties de collections ==== | ||
- | |||
- | Avec ''equal'', il est possible de comparer un partie d'une collection. Pour cela, il suffit de fournir des positions différentes que le début et la fin d'une collection. Par exemple, vous pouvez incrémenter ou décrémenter les positions de début (avec ''begin(s)+n'') et de fin (avec ''end(s)-n'') en faisant attention de ne pas donner des valeurs en dehors de la collection ou en utilisant des fonctions de recherche (''find'', que vous verrez dans un prochain chapitre). | ||
- | |||
- | Par exemple, pour comparer les quatre premiers éléments de deux collections, vous pouvez écrire : | ||
- | |||
- | <code cpp main.cpp> | ||
- | #include <iostream> | ||
- | #include <string> | ||
- | #include <algorithm> | ||
- | |||
- | int main() { | ||
- | std::string const s1 { "abcdef" }; | ||
- | std::string const s2 { "abcdEF" }; | ||
- | std::cout << std::boolalpha; | ||
- | std::cout << std::equal(begin(s1), end(s1), begin(s2), end(s2)) << std::endl; | ||
- | std::cout << std::equal(begin(s1), begin(s1)+4, begin(s2), begin(s2)+4) << std::endl; | ||
- | } | ||
- | </code> | ||
- | |||
- | affiche : | ||
- | |||
- | <code> | ||
- | false | ||
- | true | ||
- | </code> | ||
- | |||
- | La première version compare la totalité des deux chaînes (''"abcdef"'' et ''"abcdEF"'') et retourne ''false''. La seconde version compare le début de la première chaîne (à partir de ''begin(s1)'' donc ''"a"'' jusqu'au quatrième caractère ''begin(s1)+4'' donc ''"d"'') avec le début de la seconde (également ''"abcd"'') et retourne ''true''. | ||
- | |||
- | **Attention** en utilisant la notation ''begin(s)+n'', si vous sortez de la collection, cela produit une comportement indéterminé (//undefined behavior//), donc aucun message d'erreur vous prévenant qu'il y a un problème. | ||
- | |||
- | ==== Utiliser un prédicat personnalisé ==== | ||
- | |||
- | Lorsque les collections contiennent des éléments de types non comparables ou lorsque la comparaison d'égalité par défaut ne convient pas, il est possible de fournir un prédicat personnalisé dans ''std::equal''. Par exemple, si vous souhaitez comparer deux chaînes de caractères, sans prendre en compte la casse (c'est-à-dire sans prendre en compte les majuscules ou minuscules), il n'est pas possible d'utiliser l'opérateur ''=='' classique. | ||
- | |||
- | La solution dans ce cas est d'utiliser la fonction de conversion ''std::toupper'' (ou ''std::tolower'') pour convertir tous les caractères en majuscule pour faire la comparaison. Pour écrire ce prédicat, le plus simple dans ce cas est d'écrire une fonction lambda. | ||
- | |||
- | Cette fonction lambda doit faire la comparaison entre deux éléments et retourner un booléen. La signature sera la même que cela que vous avez déjà vu : | ||
- | |||
- | <code cpp> | ||
- | [](auto lhs, auto rhs){ return expression_booléenne_avec_lhs_et_rhs; } | ||
- | </code> | ||
- | |||
- | Les paramètres ''lhs'' et ''rhs'' sont les éléments des collections (des caractères dans cet exemple) qui sont comparés deux à deux. Pour convertir ces deux valeurs en majuscule, il faudra donc écrire : ''std::toupper(lhs)'' et ''std::toupper(rhs)''. Au final, la comparaison s'écrit : | ||
- | |||
- | <code cpp> | ||
- | return std::toupper(lhs) == std::toupper(rhs); | ||
- | </code> | ||
- | |||
- | Le code complet pour la comparaison est (ne pas oublier d'inclure le fichier d'en-tête ''<cctype>'' pour utiliser ''toupper'') : | ||
- | |||
- | <code cpp> | ||
- | #include <iostream> | ||
- | #include <string> | ||
- | #include <algorithm> | ||
- | #include <cctype> | ||
- | |||
- | int main() { | ||
- | std::string const s1 { "abcdef" }; | ||
- | std::string const s2 { "abcdEF" }; | ||
- | std::cout << std::boolalpha; | ||
- | std::cout << std::equal(begin(s1), end(s1), begin(s2), end(s2)) << std::endl; | ||
- | std::cout << std::equal(begin(s1), end(s1), begin(s2), end(s2), | ||
- | [](auto lhs, auto rhs){ return std::toupper(lhs) == std::toupper(rhs); }) | ||
- | << std::endl; | ||
- | } | ||
- | </code> | ||
- | |||
- | affiche : | ||
- | |||
- | <code> | ||
- | false | ||
- | true | ||
- | </code> | ||
- | |||
- | La première version prend en compte la casse et retourne ''false'' alors que la seconde version ne la prend pas en compte et considère que les deux chaînes sont identiques. | ||
- | |||
- | ===== Exercices ===== | ||
- | |||
- | * comparer vector<int> et vector<float> | ||
- | * comparer vector<int> et vector<string> (aide : utilise std::stoi) | ||
- | * comparer vector<int> et vector<string> (qui contient "un", "deux", etc.) | ||
- | * tester si palindrome (un palindrome est un mot qui peut être lu de droite à gauche ou de gauche à droite, comme par exemple "kayak" ou "radar"). | ||
- | |||
- | <code cpp main.cpp> | ||
- | #include <iostream> | ||
- | #include <string> | ||
- | #include <algorithm> | ||
- | |||
- | int main() { | ||
- | std::string const s1 { "azerty" }; // non palindromique | ||
- | std::string const s2 { "abccba" }; // palindromique | ||
- | std::cout << std::boolalpha; | ||
- | std::cout << std::equal(begin(s1), end(s1), s1.rbegin()) << std::endl; | ||
- | std::cout << std::equal(begin(s2), end(s2), s2.rbegin()) << std::endl; | ||
- | } | ||
- | </code> | ||
- | |||
- | affiche : | ||
- | |||
- | <code> | ||
- | false | ||
- | true | ||
- | </code> | ||
- | |||
- | ^ Chapitre précédent ^ [[programmez_avec_le_langage_c|Sommaire principal]] ^ Chapitre suivant ^ | ||
- | |||
- | {{tag> Cours C++}} |