1. #1
    Nouveau Candidat au Club
    Homme Profil pro
    Etudiant
    Inscrit en
    juillet 2017
    Messages
    1
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Etudiant
    Secteur : Alimentation

    Informations forums :
    Inscription : juillet 2017
    Messages : 1
    Points : 1
    Points
    1

    Par défaut Algorithmique Appliquée en C++

    Bonjour,
    Etant débutant en algorithme, j'ai un peu du mal a trouver la solution de certains exercices.
    Je travaille sur codeblocks

    Comment puis-je faire pour forcer la saisie d'une valeur de 1 et 9 en utilisant la boucle la plus adaptée ?

    Algorithme

    programme tableDeMultiplication
       val, k : entier 
    debut  
       repeter
           afficher "Entrez un nombre entier = "
           saisir val  
       jusqu’à val>=1 et val<=9  
       pour k de 1 à 10    afficher val, " * ", k, " = ", (val*k)  
       finpour 
    fin 

    Traduction en C++

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    #include <iostream>
    
    
    using namespace std ;
    
    
    int main()
    {
    int val, k ;
    
    
    do
    {
    cout << "Entrez un nombre entier = " ;
    cin >> val ;
    }
    while ( val>=1 && val<=9) ; -> Soucis ?? 
    {
    for (k >= 1 ; k <= 10 ; k++)
    {
    endl (cout << val << " * " << k << " = " << (val*k)) ;
    }
    }
    
    
    return 0 ;
    }
    [COLOR=#373737]Merrci pour votre réponse

  2. #2
    Membre émérite
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    décembre 2015
    Messages
    550
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : décembre 2015
    Messages : 550
    Points : 2 856
    Points
    2 856

    Par défaut

    Bonjour,

    while veut dire "tant que", la condition que l'on doit mettre est celle pour que la boucle continue. Or "jusqu'à" dans l'algorithme correspond à la condition pour quitter la boucle. Il donc mettre la condition inverse dans le while.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    do
    {
        ...
    } while ( val < 1  ||  val > 9 );

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    juin 2016
    Messages
    24
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 15
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : juin 2016
    Messages : 24
    Points : 37
    Points
    37

    Par défaut

    Bonjour,
    outre ce qui a été dit précédemment, on pourrait quelque peu améliorer le programme.

    On aurait donc ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
    #include <iostream>
     
     
    using namespace std ;
     
     
    int main()
    {
    int val=0;      //je préfère initialiser mes variables mais cela n'a pas d'importance
                         //pas besoin de k car tu le crées apres dans la boucle for
     
    do
    {
    cout << "Entrez un nombre entier (entre 1 et 9 inclus) = " << endl;
    cin >> val ;
    }while ( val < 1  ||  val > 9 );
     
     
    for (int k=1 ; k <= 10 ; k++)    // plus facile de déclarer k directement dans le for et de l'initialiser a 1
    {
           int resultat = k *val;    // plus clair de créer une variable
           cout << val << " * " << k << " = " << résultat << endl;
    }
     
     
    return 0 ;
    }
    Mon dernier conseil est de créer une fonction afin d'avoir une meilleur lisibilité, cela reste un court programme mais cela peut être utile sur un algorithme plus épais.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     
    #include <iostream>
     
    using namespace std ;
     
     
    int multiplication(int a){
        for (int k=1; k<=10; k++){
        int resultat= k * a;
        cout << a << " * " << k << " = " << resultat << endl;
        }
    }
     
    int main()
    {
    int val=0;      //je préfère initialiser mes variables mais cela n'a pas d'importance
     
    do
    {
    cout << "Entrez un nombre entier = " ;
    cin >> val ;
    }while ( val < 1  ||  val > 9 );
     
     
     
    cout << multiplication(val) << endl;
     
     
    return 0 ;
    }

  4. #4
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    juin 2007
    Messages
    4 948
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : juin 2007
    Messages : 4 948
    Points : 16 429
    Points
    16 429

    Par défaut

    quitte à faire des fonctions, ce n'est pas celle-là que j'aurai sorti du main() en premier.

    La fonction main() correspond à la fonctionnalité principale.
    Ici, il s'agit d'afficher la table de multiplication (par les entiers entre 1 et 10 inclus) d'un entier entre 1 et 9 demandé à l'utilisateur.

    Je m'attends à avoir un code très proche de:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int main() {
         //obtenir l'entier de l'utilisateur.
         //afficher la table de multiplication
         return 0;
    }
    L'affichage est spécifique à un programme, et n'est généralement pas réutilisable. En faire une fonction serait un détail du programme courant.
    C'est souvent une bonne idée, mais n'apporte pas grand chose.
    Ici, c'est l'objectif du programme, autant le laisser dans la fonction principale.

    La validation de donnée interactive est beaucoup plus intéressante.
    C'est une tache courante, et dont la mise en œuvre est un détail devant l'objectif du programme, au point qu'on pourrait la remplacer par la lecture des arguments d'exécution du programme.

    Voici comment je coderai cela.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int demander_int_entre(int min, int max);
     
    int main() {
        std::cout << "Quelle table de multiplication voulez-vous afficher?" << std::endl;
        const auto table_choisie = demander_int_entre(1, 9);
        std::cout << "La table de multiplication par "<< table_choisie << " est:" << std::endl;
        for (int i = 1; i <= 10; ++i) {
            std::cout << table_choisie << " * " << i << " = " << (table_choisie * i) << std::endl;
        }
     
         return 0;
    }
    Ce code est clair. Il montre ce qu'il fait, et ne laisse pas de surprise sur la partie exigée.
    J'en profite pour glisser quelques retouches:
    • J'ai renommé la variable lue pour que son nom souligne son utilité.
    • Je l'ai rendue constante, car elle n'a pas vocation à être modifiée.
    • J'ai laissé le compilateur choisir efficacement le type de cette variable, car il sait le déduire trivialement (celui retournée par la fonction).
    • J'ai supprimé la variable résultat, car c'est une variable temporaire lue une seule fois, dont le nom est mal choisi (j'aurai préféré produit, multiplication). Une variable de moins est un problème de moins
    • J'ai changé la variable de la boucle for, car les développeurs ont l'habitude d'utiliser les entiers i, j, voire k ou l dans cet ordre pour les boucles de plus en plus imbriquées.
    • J'ai aussi changé le i++ en ++i. En C++, il y a d'autres choses sur lesquelles on fait des boucles (les itérateurs), pour lesquelles les deux opérations n'ont pas le même prix.
    • J'ai retiré le using namespace std, parce que c'est très souvent une mauvaise idée, dans de vrais programmes. Il vaut mieux ne pas prendre de mauvaise habitude.


    Et maintenant, je peux passer à cette fameuse fonction demander_int_entre:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int demander_int_entre(int min, int max) {
        int valeur;
        std::cout << "Veuillez saisir un entier entre " << min << " et " << max <<": " << std::endl;
        std::cin >> valeur;
        while (valeur < min || valeur > max) {
            std::cin >> valeur;
            std::cout << valeur << "n'est pas compris entre  " << min << " et " << max <<', recommencez: ' << std::endl;
        }
        return valeur;
    }
    Je n'ai pas recouru a une boucle do while, parce que le comportement n'ai pas le même pour la premiere itération et les suivantes.
    Avant la première, j'invite l'utilisateur à répondre, tandis qu'au suivante, je lui signifie qu'il doit recommencer.


    Note 1:
    Je n'ai volontairement pas fait de demander_int_entre une template, parce que c'est largement pas le moment d'en parler, mais ca serait un cas idéal.
    En effet, c'est une fonction utilitaire, qui pourrait aussi bien marcher pour les types short, long, int, unsigned long, float, double, et peut-être même d'autres…
    Si tu veux en savoir plus sur le sujet, dis-le, j'expliquerai.

    Note 2:
    Cela n'empèche pas de faire deux fonctions, mais d'une manière générale, ce sont les détails techniques qui doivent devenir des fonctions en premier.

    Note 3:
    Pour main(), il y a un choix à faire.
    Personnellement, je considère que son rôle serait d'établir le contexte de travail, puis de lancer l'activité.
    Obtenir le contexte de travail peut être fait par la lecture des arguments de ligne de commande, d'un fichier de configuration, des variables d'environnement, ou par des questions à l'utilisateur.
    Dans un vrai programme, j'aurai effectivement fait une fonction void afficher_table_multiplication(int table, int taille = 10).
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  5. #5
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    juin 2016
    Messages
    24
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 15
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : juin 2016
    Messages : 24
    Points : 37
    Points
    37

    Par défaut

    Bonjour,
    premièrement merci pour cette réponse très complète et didactique; effectivement ton code est très pertinent.

    Toutefois, ton code est peut être trop complexe pour la personne qui a demandé l'aide ( j'ai essayé de limiter les notions avancées), par exemple:
    -retirer le n'était pas nécessaire car le programme est court et il n'y aura donc pas de confrontation entre différents namespaces et le std:: est rebutant quand on ne sait pas de quoi il s'agit (je suis passé par là je peux donc l'affirmer);
    - const auto n'est peut être pas très parlant et on pouvait se limiter a utiliser un simple const int

    De plus, une variable de moins est un problème de moins est certes vrai dans un programme lourd mais ici je pense qu'utiliser des variables quand on est débutant permet de mieux visualiser a quel point en est l'algorithme et peut être clarifier la situation.

    En revanche, j'approuve ce qui concerne la fonction demander_int_entre (j'avoue ne pas avoir eu envie de rédiger la partie gestion des entrées incorrectes proprement et m'être contenté de rajouter (entre 1 et 9) dans le premier cout).

    En ce qui concerne les templates, l'idée m'a effleuré l'esprit mais je me suis aussi rappelé le niveau de la personne, cette solution technique n'aurait eu pour elle aucun intérêt a part peut être de la décourager totalement .... Je veux tout de même bien que tu développes un peu le sujet car ma maîtrise des templates est encore assez hasardeuse et cela ne pourrait être que bénéfique pour moi.

    Enfin, comme précisé dans mon premier message, je recommande de faire des fonctions lorsque le code est volumineux mais il est vrai que cela n'était guère utile ici.

    Cordialement.

  6. #6
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    juin 2007
    Messages
    4 948
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : juin 2007
    Messages : 4 948
    Points : 16 429
    Points
    16 429

    Par défaut

    L'idée de notre forum n'est pas d'aider le débutant à résoudre son exercice, mais d'aider le débutant à devenir un bon développeur.

    C'est donc de faire les bonnes choses.
    Je ne vois pas l'intérêt de lui laisser apprendre à mettre partout des using namespace std pour après lui expliquer qu'il faut s'en débarrasser partout, et donc désapprendre.
    De même pour auto. C'est une bonne occasion de présenter la chose, sachant que c'est généralement une bonne idée de s'en servir (AAA, almost always auto).
    Il y a même un certain nombre de cas où c'est le meilleur choix.

    Et si je mentionne la template, c'est pour donner l'idée qu'il y a quelque chose à faire pour avoir un code de qualité, mais qu'effectivement c'est peut-être trop en demander pour le moment.

    En l'occurence, j'ai appris les bases des templates de fonctions après moins d'une heure de C++ (et une douzaine d'heures de C, niveau première année). Et visiblement, je n'en suis pas morte

    Je précise cela, mais ca n'enlève rien à l'intérêt de tes messages.
    Tu remarqueras justement que j'ai complété tes suggestions.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  7. #7
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    juin 2007
    Messages
    4 948
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : juin 2007
    Messages : 4 948
    Points : 16 429
    Points
    16 429

    Par défaut

    Citation Envoyé par Gwynbleidd Voir le message
    En ce qui concerne les templates, l'idée m'a effleuré l'esprit mais je me suis aussi rappelé le niveau de la personne, cette solution technique n'aurait eu pour elle aucun intérêt a part peut être de la décourager totalement .... Je veux tout de même bien que tu développes un peu le sujet car ma maîtrise des templates est encore assez hasardeuse et cela ne pourrait être que bénéfique pour moi.
    Chouette

    Commençons par un apparté sur les fonctions.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <iostream>
     
    int f(int a, int b) {
        return a+b;
    }
     
    int main() {
        std::cout << f(1, 2) << " = " << f(2, 1) << std::endl;
        return 0;
    }
    .
    Dans ce code, f est d'abord déclarée comme étant une fonction qui prend deux valeurs entières et retourne un entier. Sa définition est immédiatement faite, avec comme seul fonctionnement de retourner la somme de ses paramètres.
    main est ensuite définie pour appeler f avec comme arguments 1 et 2, puis 2 et 1
    Notez comme j'appele paramètre la variable (presque locale) de la fonction, et argument la valeur qui lui est attribuée à son appel.

    À l'exécution du programme, f calcule la somme de 1 et 2 au premier appel, puis celle de 1 et 2 au second appel, et ce sont ces deux sommes qui sont affichées.

    La compilation à généré un morceau de code paramétré, qui est utilisé à l'exécution utilisé deux fois, avec des valeurs différents.


    Passons aux templates.
    Une template est un modèle pour permettre au compilateur de générer du code qui serait répétitif. Ce peut être un modèle de fonction ou de classe.
    Je ne parlerai que des fonctions.


    Une template de fonction n'est pas une fonction, [b]maelle permet de générer des fonctions distinctes (on dit instancier).
    Une template doit être intégralement définie pour pouvoir réaliser une instanciation.

    Question syntaxe, une template est reconnaissable dans sa définition parce qu'elle commence par template < "des choses" >.
    Ce bloc sert à dire "la chose qui suit est un modèle, paramétré par "des choses".
    Ces paramètres peuvent être soit des valeurs entières, soit des types.

    Les templates sont un peu comme des fonctions, mais appelée pendant la compilation, et qui produise du code.

    Ici, nous avons la fonction suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int demander_int_entre(int min, int max) {
        int valeur;
        std::cout << "Veuillez saisir un entier entre " << min << " et " << max <<": " << std::endl;
        std::cin >> valeur;
        while (valeur < min || valeur > max) {
            std::cin >> valeur;
            std::cout << valeur << "n'est pas compris entre  " << min << " et " << max <<', recommencez: ' << std::endl;
        }
        return valeur;
    }
    Si je veux que la fonction permette de demander un long, il faut que je la recopie, en remplaçant uniquement cinq mots: les cinq fois om j'ai écrit "int".
    L'idée, c'est de créer un modèle de fonction, qui aura pour paramètre de modèle le type à obtenir. Ceci s'écrit template <typename Type>.
    Le mot clé typename sert à préciser que ce qui suis est le nom d'un type.

    Ca donne donc, dans un premier temps:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template <typename Type>
    Type demander_valeur_entre(Type min, Type max) {
        Type valeur;
        std::cout << "Veuillez saisir un entier entre " << min << " et " << max <<": " << std::endl;
        std::cin >> valeur;
        while (valeur < min || valeur > max) {
            std::cin >> valeur;
            std::cout << valeur << "n'est pas compris entre  " << min << " et " << max <<', recommencez: ' << std::endl;
        }
        return valeur;
    }
    J'ai du changer un peu le nom de la fonction, car il faut bien un nom fixe pour toutes les fonctions produites par le modèle.

    A partir de cette définition de modèle, pour tout type t, il existe une fonction nommée demander_valeur_entre<t>, chacune distincte les unes des autres.
    Cette précision est très importantes.
    Si t1 et t2 sont deux types distincts, alors demander_valeur_entre<t1> et demander_valeur_entre<t2> sont deux fonctions distinctes.
    Notamment, la fonction que j'avais appelée demander_int_entre est équivalente à demander_valeur_entre<int>.

    Cela dit, toutes ces fonctions ne sont effectivement générée par le compilateur que si le code les utilise.

    Pour l'appeler, je peux donc écrire const auto table_choisie = demander_valeur_entre<int>(1, 9);.

    On notera qu'a présent, auto devient un peu plus utile, car c'est le type retourné par la fonction générée pour le paramètre de modèle int.
    Aparté à ce sujet.

    auto encore plus utile si je dois écrire une autre template de fonction telle que demander_liste_valeurs_entre.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    template <typename T>
    std::vector<T> demander_liste_valeurs_entre(T min, T max, typename std::vector<T>::size_type quantite) {
        std::cout << "veuillez saisir " << quantite << " nombres." << std::endl;
        std::vector<T> valeurs;
        for (decltype(quantite) i = 0; i < quantite; ++i) {
            valeurs.push_back( demander_valeur_entre(min, max) );
        }
        return valeurs;
    }
    Le decltype est un operateur (comme sizeof) qui à pour valeur le type de la chose donnée en argument. Ici, le type de quantité à savoir typename std::vector<T>::size_typeCe typename-ci sert à confirmer au compilateur que oui, cette size_type est bien un nom de type. Il faut le préciser, car T, argument de std::vector<T> est un paramètre de la template en cours de définition.


    Il y a une grosse subtilité, bien pratique: la déduction automatique des paramètres templates lors de l'appel des fonctions.
    On peut ne pas préciser les paramètres templates, s'ils peuvent être déduits des arguments de la fonction. Ou seulement certains.
    Ainsi, il est possible d'écrire const auto table_choisie = demander_valeur_entre(1, 9);. La template sélectionnée est celle où T est decltype(1) et decltype(9), c'est à dire int.

    Le programme devient maintenant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    #include <iostream>
     
    template <typename Type>
    Type demander_valeur_entre(Type min, Type max) {
        Type valeur;
        std::cout << "Veuillez saisir un entier entre " << min << " et " << max <<": " << std::endl;
        std::cin >> valeur;
        while (valeur < min || valeur > max) {
            std::cin >> valeur;
            std::cout << valeur << "n'est pas compris entre  " << min << " et " << max <<', recommencez: ' << std::endl;
        }
        return valeur;
    }
     
    int main() {
        std::cout << "Quelle table de multiplication voulez-vous afficher?" << std::endl;
        const auto table_choisie = demander_valeur_entre(1, 9);
        std::cout << "La table de multiplication par "<< table_choisie << " est:" << std::endl;
        for (int i = 1; i <= 10; ++i) {
            std::cout << table_choisie << " * " << i << " = " << (table_choisie * i) << std::endl;
        }
     
        return 0;
    }
    Le point très important, c'est que la template est instanciée à la demande. En l'occurence dans ce programme, seule demander_valeur_entre<int> est générée, et seulement parce qu'elle sert en ligne 17.


    C'est peu intéressant dans l'absolu, parce qu'on n'utilise la template qu'avec un seul type. Mais on peut la placer dans un fichier d'en-tête, dont on pourra se servir dans d'autres programmes.
    C'est ce genre de chose qu'on trouve dans les en-têtes de la STL (tels que iostream, par exemple)

    Par contre, il y a une chose importante à faire, et qui n'est pas faite encore.
    Une chose très très importante.
    Valider le paramètre template.

    une template est appelable avec n'importe qu'elle type, et peut échouer très lamentablement.
    J'ai le droit d'écrire demander_valeur_entre(std::cout, std::cout), c'est une séquence syntaxiquement valide.
    Par contre, le code de la fonction générée ne compile pas, car le type de std::cout n'est pas comparable (n'a pas d'opérateur < valide), n'est pas lisible (std::cin >> valeur) ne peut pas compiler, etc.

    Et le gros soucis, c'est que le message d'erreur va être très très long.
    L'idée, c'est d'introduire des prérequis à vérifier lors de la compilation.
    C'est à cela que sert le mot clé static_assert.
    Il prend la forme d'une fonction ayant deux arguments: une expression booleenne constante (calculable à la compilation) et une chaine de caractère littérale à afficher en cas d'erreur.
    Si l'expression est fausse, le compilateur s'arrête et affiche un "diagnostique" (c'est le terme légal) contenant au moins le message spécifié.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include <type_traits>
    template <typename Type>
    Type demander_valeur_entre(Type min, Type max) {
        static_assert( std::is_arithmetic<Type>::value , "Type doit être un type numérique.");
        Type valeur;
        std::cout << "Veuillez saisir un entier entre " << min << " et " << max <<": " << std::endl;
        std::cin >> valeur;
        while (valeur < min || valeur > max) {
            std::cin >> valeur;
            std::cout << valeur << "n'est pas compris entre  " << min << " et " << max <<', recommencez: ' << std::endl;
        }
        return valeur;
    }
    std::is_arithmetic est une template de classe trouvée dans type_traits, qui a le bon gout de définir un bool, std::is_arithmetic<Type>::value qui vaut vrai si Type est arithmétique.
    Note: C'est usuellement à ce moment-là qu'on parle de "méta programmation". Autre sujet.

    Il faudrait de même vérifier que Type est lisible depuis std::cin, mais ce serait assez lourd, pour aucune valeur ajoutée à l'explication.


    Donc, en prenant le soin de créer un fichier d'en-tête dédié, on obtient:
    Code demander_valeur.hpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #include <iostream>
    #include <type_traits>
     
    template <typename Type>
    Type demander_valeur_entre(Type min, Type max) {
        static_assert( std::is_arithmetic<Type>::value , "Type doit être un type numérique.");
        Type valeur;
        std::cout << "Veuillez saisir un entier entre " << min << " et " << max <<": " << std::endl;
        std::cin >> valeur;
        while (valeur < min || valeur > max) {
            std::cin >> valeur;
            std::cout << valeur << "n'est pas compris entre  " << min << " et " << max <<', recommencez: ' << std::endl;
        }
        return valeur;
    }
    Code main.cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include <iostream>
    #include "demander_valeur.hpp"
     
    int main() {
        std::cout << "Quelle table de multiplication voulez-vous afficher?" << std::endl;
        const auto table_choisie = demander_valeur_entre(1, 9);
        std::cout << "La table de multiplication par "<< table_choisie << " est:" << std::endl;
        for (int i = 1; i <= 10; ++i) {
            std::cout << table_choisie << " * " << i << " = " << (table_choisie * i) << std::endl;
        }
     
        return 0;
    }

    Avertissement: contrairement aux fonctions (non inline), une template doit être intégralement définie pour servir, elle ne peut pas être séparée en une déclaration dans un en-tête et une définition dans un fichier d'implémentation .cpp.

    Pour des informations plus précises, il faut regarder dans une référence du langage.
    J'utilise personnellement cppreference.com. Les pages utiles sont accessibles à partir de la page templates.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  8. #8
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    juin 2016
    Messages
    24
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 15
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : juin 2016
    Messages : 24
    Points : 37
    Points
    37

    Par défaut

    Pour le premier message:
    ne t'inquiète pas, j'essaie d'aider les débutants quand je sens que cela reste abordable pour moi et que je peux avoir un certain recul. Toutefois, lorsqu'il advient que mes conseils sont erronés et bien je suis content que quelqu'un me reprenne, cela est tout aussi instructif pour moi^^

    Pour le second message:
    je te remercie grandement pour l'explication sur les templates, ce fut très intéressant et assez détaillé pour ne pas être perdu.
    Ayant compris ce que tu m'as expliqué, je n'ai pas vraiment de questions, j'irais voir du côté des sources que tu m'as fournies.

    En tout cas, un grand merci d'avoir pris le temps de me livrer ce petit 'cours appliqué' sur les templates!

    Cordialement.

Discussions similaires

  1. Rech cours de base en Algorithmique
    Par ALKATRAZ dans le forum Général Algorithmique
    Réponses: 3
    Dernier message: 19/12/2002, 19h07
  2. appliquer des textures de taille 2n+1
    Par Katsuo chris dans le forum DirectX
    Réponses: 4
    Dernier message: 14/11/2002, 00h11
  3. [VB6][Formulaire]Appliquer un Scrollbar a une Form
    Par Boil dans le forum VB 6 et antérieur
    Réponses: 3
    Dernier message: 09/11/2002, 03h51
  4. logiciel de programmation en Algorithmique
    Par Thomas Lebrun dans le forum Général Algorithmique
    Réponses: 11
    Dernier message: 08/11/2002, 22h18
  5. compression de données du point de vue algorithmique
    Par GoldenEye dans le forum Général Algorithmique
    Réponses: 9
    Dernier message: 26/06/2002, 15h51

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo