====== Partie 1 : Manipuler un ensemble d'arguments ====== [[in204:tds:sujets:td12_2023|TD12]] ===== Question 1 ===== Ecrire une fonction ''print'' qui prend un nombre libre d'entiers en paramètres et qui affiche ces entiers sur la console. Pour ce faire, nous vous conseillons d'autiliser la classe ''std::initializer_list'' comme argument de la fonction. Un [[https://en.cppreference.com/w/cpp/utility/initializer_list|std::initializer_list]] permet d'accéder à la une liste de valeurs de type ''T'' qui est écrit sous la forme suivante : std::initializer_list list_of_values = {1, 3, 4, 2 }; Cette liste de valeur n'est pas modifiable. Il est seulement possible de la lire en lecture comme un containeur classique. Les fonctions ''begin()'', ''end()'' ainsi que ''size()'' permettent d'accéder aux valeurs stockées dans la liste. void print(std::initializer_list arguments) { auto it = arguments.begin(), end_it = arguments.end(); if (it != end_it) { std::cout << *it; while (++it != end_it) std::cout << ", " << *it; } } ===== Question 2 ===== Généraliser cette fonction à d'autres types que les types entiers. Cette fois-ci, nous attaquons les choses un peu plus complexes. En effet, pour cela, vous allez utiliser les [[https://en.cppreference.com/w/cpp/language/parameter_pack|packs de paramètres]] des fonctions et des classes templatées. Quand nous écrivons : * ''template f(Args... arguments)'', cela signifie que la fonction prend comme arguments un ensemble d'arguments qui ont des types différents. La variable ''arguments'' fait référence à l'ensemble des valeurs ayant chacun un type différent, c'est pour cela que l'on parle de **pack de paramètres**. Attention, il n'est pas possible d'accéder aux données individuelles présentes dans le **pack de paramètres**. * l'opérateur ''sizeof...(Args)'' permet d'obtenir le nombres d'arguments passés à la fonction ou spécifié comme paramètres de la classe. * En fait, les packs de paramètres servent à être passés directement à une fonction. Ainsi nous pouvons écrire le code suivant : void number_of_args() { std::cout << "no arguments"; } template void number_of_args(T) { std::cout << "one argument"; } template void number_of_args(T1, T2) { std::cout << "two arguments"; } template void func(Args... arguments) { return number_of_args(arguments...); } va appeller en fonction du nombre d'arguments l'une des fonctions ''number_of_args''. Nous pouvons désormais imaginer une approche récursive pour compter le nombre d'arguments en implantant le code suivant : template int number_of_args(T first_argument, Args... arguments) { return 0; } template int number_of_args(T first_argument, Args... arguments) { return 1 + number_of_args(arguments); } L'appel de la fonction ''number_of_args'' qui suit : std::cout << number_of_args(1, "e", 2.0, 'c') << "\n"; retournera ''4''. ==== Question 2.1 ==== Expliquer comment le code a été exécuté ? le code ''number_of_args(1, "e", 2.0, 'c')'' correspond à appeller la fonction : ''number_of_args number_of_args(1, "e", 2.0, 'c')'' avec : * T = int, * Args.. = const char*, double, char Cette fonction appelle récursivement ''1 + number_of_args("e", 2.0, 'c')'', soit ''number_of_args number_of_args("e", 2.0, 'c')'' avec : * T = const char*, * Args.. = double, char puis ensuite ''1 + number_of_args(2.0, 'c')'', soit ''number_of_args number_of_args("e", 2.0, 'c')'' avec : * T = double, * Args.. = char puis ensuite ''1 + number_of_args('c')'', soit ''number_of_args number_of_args("e", 2.0, 'c')'' avec : * T = char, * Args.. = puis ensuite ''1 + number_of_args()'', soit ''number_of_args number_of_args()'' avec : * Args.. = qui elle retroune ''0''. Ce qui génère bien le résultat ''4''. ==== Question 2.2 ==== En vous inspirant du code précédant, proposer une fonction ''print'' qui prend un nombre variable de paramètres qui peuvent avoir des types différents et qui imprime cette liste de paramètres sur la console. template void print(T first_argument) { std::cout << first_argument; } template void print(T first_argument, Args... arguments) { std::cout << first_argument; if (sizeof...(Args) > 0) std::cout << ", "; print(arguments...); } ====== Navigation ====== Partie 2: [[.part2|Mesurer le temps passé par une fonction]]