====== Partie II – Spécialisation par contraintes ====== [[in204:tds:sujets:td6|TD6]] ===== Question n°1 ===== Nous considérons toujours notre code affichant le contenu d'un conteneur tel que défini dans la [[in204:tds:sujets:td6:part1|première partie]]. template> std::basic_ostream& operator << (std::basic_ostream& aStream, const containerT& aContainer) { aStream << "{"; auto end = aContainer.end(); for(auto it = aContainer.begin(); it != end;) { aStream << *it ++; if(it != end) aStream << ", "; } aStream << "}"; } ==== Question n°1.1 ===== Déterminer ce qui va caractériser un conteneur pouvant être pris comme argument par la fonction précédente ? En fait, il est attendu que le conteneur fournisse deux méthodes : * `begin()`: retournant un itérateur marquant le début de la séquence, * `end()`: retournant un itérateur marquant le fin de la séquence. L'itérateur qui est retourné doit supporter : * l'accès en lecture des données stockées dans le conteneur, * le parcours en avant. Il n'a pas besoin de supporter le multipasse. ==== Question n°1.2 ===== Implanter un concept qui permet de formaliser les exigences que vous venez de formuler ? template concept Browsable = requires (const T& a) { { a.begin() } -> std::forward_iterator; { a.end() } -> std::forward_iterator; }; ==== Question n°1.3 ===== Ajouter les contraintes à l'opérateur %%<<%% qui a été défini pour un conteineur. template> requires Browsable std::basic_ostream& operator << (std::basic_ostream& aStream, const containerT& aContainer) { aStream << "{"; auto end = aContainer.end(); for(auto it = aContainer.begin(); it != end;) { aStream << *it ++; if(it != end) aStream << ", "; } aStream << "}"; return aStream; } ==== Question n°1.4 ===== Introduisez une implantation de l'opérateur `<<` qui pour tout type affiche 'NONE'. template> std::basic_ostream& operator << (std::basic_ostream& aStream, const T& aContainer) { std::cout << "NONE"; return aStream; } ===== Question n°2 ==== Nous avons deux fonctions pour effectuer un tri, l'algorithme simple de tri que nous avons implanté et l'algorithme ``std::sort`` fourni par la STL. Cependant notre algorithme fonctionne pour des itérateurs qui ne supportent pas l'accès indexé tandis que l'algorithme ``std::sort`` est un quicksort et nécessite un accès indexé mais qui est plus rapide. Modifier le code de ``std::simple_sort`` pour appeller ``std::sort`` si jamais les itérateurs sont des itérateurs supportant l'accès direct (``std::random_access_iterator``). template void simple_sort(iterator start, iterator end) requires(std::forward_iterator && ! std::random_access_iterator && std::input_or_output_iterator) { std::cout << "Insertion Sort\n"; for(;start != end; start ++) { auto it = start; it++; for(;it != end; it ++) { // Compare si les deux elements sont dans le bon ordre. if (*start > *it) std::swap(*start, *it); } } } template void simple_sort(iterator start, iterator end) requires(std::random_access_iterator && std::input_or_output_iterator) { std::cout << "Quicksort\n"; return std::sort(start, end); } Et nous exécutons le code suivant : { std::list l = {1, 7, 3, 4, 9, 2, 5}; std::vector v(l.begin(), l.end()); simple_sort(l.begin(), l.end()); std::cout << l << std::endl; simple_sort(v.begin(), v.end()); std::cout << v << std::endl; qui génèrera la sortie suivante: Insertion Sort {1, 2, 3, 4, 5, 7, 9} Quicksort {1, 2, 3, 4, 5, 7, 9}