bonjour
ne pas tenir compte de ma question précédente
bonjour
ne pas tenir compte de ma question précédente
Désolé mais pour moi ce n'est pas un tutoriel et encore moins un cours car au final on apprend peu de choses tellement le code est incompréhensible.
Il aurait mérité plus d'explications et de détails...pour que ce soit un minimum ludique.![]()
Joli le déterrage, alors que la dernière intervention datais de ... trois ans.
Ceci dit, nous sommes en face d'un article, qui explique parfaitement le point de vue de l'auteur. Il n'a jamais été question d'en faire un tutoriel
Si le code t'a semblé obscure, je pencherais volontiers d'avantage pour le fait qu'il te manque quelques concepts de base ou quelque notions de C++ que pour autre chose.
Bien sur, étant particulièrement à l'aise avec le langage, je ne suis sans doute pas le mieux placé pour parler de la difficulté du code, mais je n'ai rien trouvé de bien compliqué dans les explications
Enfin, il n'y a rien à faire: la programmation oscille entre la science exacte et l'art, ce qui fait que, au delà d'un certain niveau, la ludicité n'a plus vraiment sa place: elle doit la céder à l'exactitude. Et c'est le cas de cet article![]()
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
En relisant l'article, je vois que l'auteur demande à l'utilisateur de lui passer des callbacks pour décider quoi faire à chaque étape de lecture du fichier CSV :
Cette conception ne m'avait pas choqué à l'époque, mais elle me gène aujourd'hui. En fait, je trouve cette conception tout à fait justifiée pour l'époque où a été écrit cet article, en 2015, donc à l'époque du C++14. Mais je me dis qu'elle est surtout justifiée par les limitations du C++ de l'époque et de la bibliothèque standard de l'époque et qu'il faudra privilégier une autre approche en C++20.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 std::function<bool(string_type const &)> comment_handler; std::function<bool(string_type const &)> field_handler; std::function<bool()> end_line_handler; std::function<bool()> end_file_handler; std::function<void(csv_error,int,int)> error_handler;
Je vais prendre un exemple basique et faire un parallèle avec le langage Python. Admettons qu'un fichier CSV représente une liste d'utilisateurs, sous la forme d'un utilisateur par ligne. Parmi les champs, l'un d'eux contient le nom de l'utilisateur et un autre vaut 0 ou 1 selon que l'utilisateur soit actif ou inactif. On veut afficher la liste des noms des utilisateurs actifs.
En Python, on peut facilement découper le code en plusieurs niveaux d'abstractions.
On peut partir de csv.reader qui retourne un itérable de listes de chaînes (une liste = une ligne ; une chaîne = une cellule). Appelons my_reader cet itérable.
Ensuite, si on définit une fonction fn convert_row_to_user(row: List[str]) -> User qui prend en paramètre une liste de chaînes et retourne un objet de type User, alors users = map(convert_row_to_user, my_reader) crée un itérable d'objets de type User à partir de l'itérable de départ.
Admettons que la classe User contienne une propriété active. On peut alors écrire active_users = filter(lambda user: user.active, users) pour créer un itérable d'objets de type User qui ne contient que les utilisateurs actifs.
Admettons que la classe User contienne une propriété name. On peut alors écrire active_user_names = map(lambda user: user.name, active_users) pour créer un itérable de chaînes qui correspond aux noms des utilisateurs actifs.
Précisons que l'évaluation est paresseuse : c'est en parcourant les éléments de l'itérable active_user_names qu'on lit les lignes du fichier CSV. Tant qu'on n'a pas encore atteint la fin de l'itérable, on n'a pas encore lu en entier le fichier CSV.
L'un des avantages est que l'on peut facilement découper le code en sous-fonctions réutilisables. Par exemple, on peut avoir une fonction get_active_user_names qui appelle une sous-fonction get_active_users qui appelle une fonction get_users.
Mais, si on remplace l'itérable de départ par un système de callbacks comme dans l'article, ça casse tout dans le code qui utilise le parseur de fichier CSV : au lieu d'écrire du beau code avec des fonctions décomposées en sous-fonctions comme on veut, de la propagation d'erreur lisible, des éventuelles boucles, etc., on se retrouve à coder une machine à états en partie monolithique dont la maintenabilité décroît avec la complexité du code qui est exécuté avant la fin de la lecture du fichier CSV.
En C++17, on pourrait concevoir le parseur de fichier CSV sous la forme d'un range dont les éléments auraient un type du genre std::variant<comment, field, end_line, error> (la fin du fichier se traduirait par la fin du range).
Par dessus, l'utilisateur pourrait créer un range dont chaque élément représente une ligne de fichier CSV. En cas d'erreur de lecture, on lance une exception. Ce type de code devrait être facilité en C++20 avec les coroutines.
Ensuite, pour que l'utilisateur puisse, comme dans l'exemple en Python, générer facilement un range d'utilisateurs par dessus le range de lignes puis générer facilement un range d'utilisateurs actifs par dessus le range d'utilisateurs, on devrait aussi avoir les équivalents de filter et map en C++20 (std::views::filter et std::views::transform). Il faudra faire attention à la gestion de la mémoire, mais le code devrait rester lisible.
Mais l'article présent date de 2015 où il n'y avait ni std::variant du C++17, ni les fonctionnalités sympathiques qui arriveront en C++20, donc c'est tout à fait normal que l'auteur ait choisi une conception avec un système de callbacks. Les limitations du langage conditionnent la manière à laquelle on conçoit les interfaces.
Partager