====== 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}