IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Affichage des résultats du sondage: Pourquoi C et C++ auraient-ils encore de nombreuses années devant eux ?

Votants
75. Vous ne pouvez pas participer à ce sondage.
  • C et C++ permettent d'avoir plus de contrôle sur le matériel

    41 54,67%
  • C et C++ vous permettent d'écrire du code très efficace

    38 50,67%
  • Les langages C et C++ sont portables

    35 46,67%
  • C et C++ sont des langages qui évoluent

    19 25,33%
  • C et C++ sont largement utilisés

    48 64,00%
  • C++ a peut-être de l'avenir, mais je doute que ça soit le cas de C

    8 10,67%
  • C a peut-être de l'avenir, mais je doute que ça soit le cas de C++

    3 4,00%
  • Je pense qu'ils n'ont plus beaucoup d'années devant eux

    6 8,00%
  • Autre (à préciser)

    3 4,00%
  • Pas d'avis

    3 4,00%
Sondage à choix multiple
Langages de programmation Discussion :

Pourquoi les langages C et C++ auraient-ils encore de nombreuses années devant eux ?


Sujet :

Langages de programmation

  1. #241
    Membre régulier
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2017
    Messages
    36
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

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

    Informations forums :
    Inscription : Août 2017
    Messages : 36
    Points : 95
    Points
    95
    Par défaut
    Plus sérieusement ceci dit, je ne suis pas sûr que citer Microsoft, dont le code source est notoirement incompréhensible, soit un argument recevable. On entend moins souvent parler de Facebook et Google en ce qui concerne la qualité du code, mais je ne doute pas qu'elle soit assez faible.

  2. #242
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par _Bérenger_ Voir le message
    Plus sérieusement ceci dit, je ne suis pas sûr que citer Microsoft, dont le code source est notoirement incompréhensible, soit un argument recevable. On entend moins souvent parler de Facebook et Google en ce qui concerne la qualité du code, mais je ne doute pas qu'elle soit assez faible.
    Si c'est à MFC que tu penses, ça commence à dater et MS a peut-être évolué depuis... Perso, je ne serais pas étonné que les codes de MS, Facebook et Google soient de bonne qualité. Ils ont de bons développeurs et ils sont bien placés pour savoir que le code pourri est rarement rentable à long terme. D'ailleurs Facebook développe et utilise ses propres outils d'analyse de code (https://github.com/facebook/pfff), j'imagine que les autres en utilisent aussi.
    Dernière modification par Invité ; 03/02/2018 à 23h20.

  3. #243
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Citation Envoyé par SimonDecoline Voir le message
    Si c'est à MFC que tu penses, ça commence à dater et MS a peut-être évolué depuis...
    Et surtout, parce qu'on l'oublie , MFC a été créée avant la norme C++98 qui apporte un peu de réflexion (RTTI) et la STL.

    Je n'ai pas connu cette période et des demandes C++ de l'époque, mais effectivement, MFC a des macros pour la réflexion : DECLARE_DYNAMIC, DECLARE_DYNCREATE, ...

  4. #244
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 471
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 471
    Points : 6 110
    Points
    6 110
    Par défaut
    Citation Envoyé par thierryc Voir le message
    Cela est possible car je n'active pas en production le "range checking". C'est une option que l'on peut activer ou non. C'est bien entendu une erreur de ma part sur un développement non testé que de ne pas l'avoir activé.
    Quand l'option est activée, une exception est levée lorsque le nombre sort de l'intervalle.
    Du coup, concernant le code en Pascal, j'ai la confirmation qu'il s'agit de contrôles à l'exécution, pas à la compilation.
    Je présume que le fait que la syntaxe pour déclarer les bornes des types d'entier soit standardisée dans le langage facilite la mise en place d'outils d'analyse statique de code pour détecter les erreurs de programmation, ce qui est une bonne chose. Mais c'est moins que ce que j'espérais.

    Dans le code en Ada, visiblement, c'est pareil. On a une manière standard de déclarer des bornes de types d'entiers à la compilation, mais les contrôles se font à l'exécution.

    Citation Envoyé par Aurelien.Regat-Barrel Voir le message
    Par exemple, avec la fmt lib, le code suivant échoue à compiler :

    Code cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    fmt::prinf("Bonjour {}, bienvenue sur {}", userName); // 2eme paramètre manquant

    Le code qui (in)valide le nombre d'arguments et qui traditionnellement est exécuté au runtime est ici aussi exécuté au moment de la compilation.
    Il y a une petite faute de frappe dans le nom de la fonction. Je présume que c'est fmt::print, mais je pense que tu te trompes sur le contrôle à la compilation.
    J'ai jeté un œil dans le code source de fmt et je ne vois pas de tel contrôle à la compilation. Extrait de "format.cc" :
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) {
      MemoryWriter w;
      w.write(format_str, args);
      std::fwrite(w.data(), 1, w.size(), f);
    }
     
    FMT_FUNC void print(CStringRef format_str, ArgList args) {
      print(stdout, format_str, args);
    }
    (FMT_FUNC est une macro qui vaut soit vide, soit inline, selon que la macro FMT_HEADER_ONLY soit définie ou non.)

    Sur le site de fmt, quand ils parlent de contrôle à la compilation, c'est sur le type des caractères, pas sur le nombre d'arguments en fonction du format :
    Where possible, errors are caught at compile time. For example, the code
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    fmt::format("Cyrillic letter {}", L'\x42e');
    produces a compile-time error because wide character L'\x42e' cannot be formatted into a narrow string. You can use a wide format string instead:
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    fmt::format(L"Cyrillic letter {}", L'\x42e');

  5. #245
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 730
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 730
    Points : 15 132
    Points
    15 132
    Par défaut
    Bonjour,

    à propos du "range checking" :
    Citation Envoyé par Pyramidev Voir le message
    Du coup, concernant le code en Pascal, j'ai la confirmation qu'il s'agit de contrôles à l'exécution, pas à la compilation.
    Euh, dans Lazarus (compilo FreePascal) je l'ai à la compilation (oublié de le signaler hier) :
    Code pascal : 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
    function ConvertirNombreEntre00et10( unEntier: TUnites; unContexte: TContexteLangue = clParDefaut): TNombreEnChaine;
    begin
      case unEntier of
         0  : result := rsZero;
         1  : result := rsUn;
         2  : result := rsDeux;
         3  : result := rsTrois;
         4  : result := rsQuatre;
         5  : result := rsCinq;
         6  : result := rsSix;
         7  : result := rsSept;
         8  : result := rsHuit;
         9  : result := rsNeuf;
         10 : result := rsDix; // Warning: range check error while evaluating constants
         else
           raise EConversioNombre.Create( eUniteNonComprise) ;
      end;
    end;
    Mais ce n'est qu'un "Warning" et donc ça produit un exécutable, qui a l'air de fonctionner (mais je n'ai pas fait de tests poussés).

    Pour m'en sortir, en haut ligne d'origine, et dessous ma correction (pas creusé plus loin) :
    Code pascal : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    implementation
     
    //?? type TUnites = 0..9;
    type TUnites = 0..10;

    Bon dimanche,
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

  6. #246
    Membre régulier
    Inscrit en
    Décembre 2004
    Messages
    123
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 123
    Points : 97
    Points
    97
    Par défaut
    Citation Envoyé par Pyramidev Voir le message
    Du coup, concernant le code en Pascal, j'ai la confirmation qu'il s'agit de contrôles à l'exécution, pas à la compilation.
    Je présume que le fait que la syntaxe pour déclarer les bornes des types d'entier soit standardisée dans le langage facilite la mise en place d'outils d'analyse statique de code pour détecter les erreurs de programmation, ce qui est une bonne chose. Mais c'est moins que ce que j'espérais.

    Dans le code en Ada, visiblement, c'est pareil. On a une manière standard de déclarer des bornes de types d'entiers à la compilation, mais les contrôles se font à l'exécution.


    Il y a une petite faute de frappe dans le nom de la fonction. Je présume que c'est fmt::print, mais je pense que tu te trompes sur le contrôle à la compilation.
    J'ai jeté un œil dans le code source de fmt et je ne vois pas de tel contrôle à la compilation. Extrait de "format.cc" :
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) {
      MemoryWriter w;
      w.write(format_str, args);
      std::fwrite(w.data(), 1, w.size(), f);
    }
     
    FMT_FUNC void print(CStringRef format_str, ArgList args) {
      print(stdout, format_str, args);
    }
    (FMT_FUNC est une macro qui vaut soit vide, soit inline, selon que la macro FMT_HEADER_ONLY soit définie ou non.)

    Sur le site de fmt, quand ils parlent de contrôle à la compilation, c'est sur le type des caractères, pas sur le nombre d'arguments en fonction du format :
    Bonjour,
    Excuse-moi si je t'ai induit en erreur. Les contrôles d'intervalle se font à la compilation le plus possible et à l’exécution lorsque le compilateur ne peut pas déduire qu'il y a une erreur certaine, par exemple lorsqu'on assigne un entier à une variable de type intervalle. C'est sûr, souple et efficace. Essaye par toi-même. FPC et lazarus (ou codeTyphon) sont libres.

  7. #247
    Membre régulier
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2017
    Messages
    36
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

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

    Informations forums :
    Inscription : Août 2017
    Messages : 36
    Points : 95
    Points
    95
    Par défaut
    Citation Envoyé par Pyramidev Voir le message
    j'avais écrit en C++ un code qui convertissait un nombre en lettres en français.
    Citation Envoyé par thierryc Voir le message
    ci-dessous le source de l'unité de conversion en Pascal.
    J'ai repris le code de Thierryc et cherché à l'implémenter en C++. En C++ il n'y a pas d'entier borné en natif et je suis donc obligé de créer une classe template pour cela.

    Plusieurs remarques:
    1. L'implémentation de la classe "bounded_integer" est moche car il faut implémenter tous les opérateurs sur les entiers et avec les entiers d'un autre type (l'arrivée du "spaceship operator" en C++20 devrait quand même alléger ce travail). Je voulais aussi une conversion implicite si la conversion est sûre (par exemple conversion de [0,9] vers [0,99]), mais explicite si elle est risquée (de [0,9] à [0,6]), et pour cela je dois utiliser des SFINAE avec std::enable_if.

    2. Une fois ce travail fait, cependant, je ne vois pas de différence flagrante avec le Pascal

    3. J'ai corrigé des problèmes sans rapport avec le langage:
    - Mes unités vont bien de 0 à 9 selon la définition mathématique conventionnelle
    - Il n'y a pas de récursion mutuelle (dépendance cyclique).

    4. Lors de la traduction, je me suis rendu compte de plusieurs problèmes du code:
    - certaines fonctions n'utilisent pas leurs arguments (exemple: unContexte n'est pas utilisé dans ConvertirNombreEntre11et19)
    - la sureté de type en Pascal (pareil en C++) n'est pas du tout complète. Par exemple, ConvertirNombreEntre11et19, ConvertirNombreEntre70et79, ConvertirNombreEntre80et89, ConvertirNombreEntre90et99 ont toutes comme préconditions un nombre [11,19], [70,79]... mais cette précondition n'est pas forcée par le type puisque l'argument est dans tous les cas dans [0,99]
    - certaines fonctions lancent des exceptions si on dépasse les bornes (ex : ConvertirNombreEntre00et10) d'autres non (ex : ConvertirNombreEnChaine)

    5. J'ai essayé de passer le plus de fonctions en "constexpr" pour qu'elles puissent être évaluées à la compilation quand leurs paramètres le sont. Mais ce n'est pas possible pour les fonctions qui renvoient des std::string car std::string n'est pas constexpr. Pour bien faire, il faudrait utiliser un autre type de chaîne qui soit constexpr. Ceci dit, les erreurs qui reposent sur les types sont bien vérifiées à la compilation (j'en ai d'ailleurs eu en compilant)

    6. Finalement, il me semble que le code est un peu meilleur par rapport au code de Thierryc grâce à 3), mais je pense qu'il n'est pas bon. En effet, je pense que cette idée de faire reposer la sûreté des intervalles sur le système de type est mauvaise: c'est lourd est ça n'est pas exhaustif (cf. 4.). À mon avis, si on veut vraiment avoir plus de sûreté, il faut donner des préconditions dans chaque fonction qui en requière.

    Voici le code:


    Code c++ : 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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    // bounded_integer.h
    #include <exception>
    #include <type_traits>
     
    class bounded_integer_underflow : public std::exception {};
    class bounded_integer_overflow : public std::exception {};
     
    template<class Integer, Integer min, Integer max>
    class bounded_integer {
      private:
        Integer data;
     
        template<class Integer0, Integer0 min0, Integer0 max0>
        friend class bounded_integer;
      public:
        bounded_integer(const bounded_integer&) = default;
        bounded_integer& operator=(const bounded_integer&) = default;
     
        constexpr // pour utilisation dans un contexte connu à la compilation (marche aussi à l'exécution)
        explicit // explicit garantie qu'il n'y aura pas de conversion implicite
        bounded_integer(Integer i)
          : data(i)
        {
          if (i<min) throw bounded_integer_underflow(); 
          if (i>max) throw bounded_integer_overflow(); 
        }
     
        template<class Integer0, Integer0 min0, Integer0 max0>
        constexpr
        // Conversion implicite...
        bounded_integer(bounded_integer<Integer0,min0,max0> i, std::enable_if_t< (min0>=min) && (max0<=max) >* tag=0) // ...car conversion sûre
          : data(i.data)
        {
          if (i.data<min) throw bounded_integer_underflow(); 
          if (i.data>max) throw bounded_integer_overflow(); 
        }
     
        template<class Integer0, Integer0 min0, Integer0 max0>
        constexpr
        explicit // Pas de conversion implicite...
        bounded_integer(bounded_integer<Integer0,min0,max0> i, std::enable_if_t< (min0<min) || (max0>max) >* tag=0) // ...car conversion risquée
          : data(i.data)
        {
          if (i.data<min) throw bounded_integer_underflow(); 
          if (i.data>max) throw bounded_integer_overflow(); 
        }
     
      // comparaisons
        /// égalité
        template<class Integer0> friend constexpr auto // on peut vouloir comparer à un nombre d'un autre type
        operator==(bounded_integer i, Integer0 j) -> int {
          return i.data == j;
        }
        template<class Integer0> friend constexpr auto
        operator==(Integer0 i, bounded_integer j) -> int {
          return j*i; // symetrique 
        }
        template<class Integer0, Integer0 min0, Integer0 max0>
        friend constexpr auto
        operator==(bounded_integer i, bounded_integer<Integer0,min0,max0> j) -> int { // specialisation
          return i.data == j.data;
        }
        /// inégalité
        template<class Integer0> friend constexpr auto
        operator!=(bounded_integer i, Integer0 j) -> int {
          return !(i==j);
        }
        template<class Integer0> friend constexpr auto
        operator!=(Integer0 i, bounded_integer j) -> int {
          return !(i==j);
        }
        template<class Integer0, Integer0 min0, Integer0 max0>
        friend constexpr auto
        operator!=(bounded_integer i, bounded_integer<Integer0,min0,max0> j) -> int {
          return !(i==j);
        }
        /// inférieur 
        template<class Integer0> friend constexpr auto
        operator<(bounded_integer i, Integer0 j) -> int {
          return i.data<j;
        }
        template<class Integer0> friend constexpr auto
        operator<(Integer0 i, bounded_integer j) -> int {
          return i<j.data;
        }
        template<class Integer0, Integer0 min0, Integer0 max0>
        friend constexpr auto
        operator<(bounded_integer i, bounded_integer<Integer0,min0,max0> j) -> int {
          return i.data<j.data;
        }
        // inf ou égal
        template<class Integer0> friend constexpr auto
        operator<=(bounded_integer i, Integer0 j) -> int {
          return i.data<=j;
        }
        template<class Integer0> friend constexpr auto
        operator<=(Integer0 i, bounded_integer j) -> int {
          return i<=j.data;
        }
        template<class Integer0, Integer0 min0, Integer0 max0>
        friend constexpr auto
        operator<=(bounded_integer i, bounded_integer<Integer0,min0,max0> j) -> int {
          return i.data<=j.data;
        }
        // supérieur
        template<class Integer0> friend constexpr auto
        operator>(bounded_integer i, Integer0 j) -> int {
          return i.data>j;
        }
        template<class Integer0> friend constexpr auto
        operator>(Integer0 i, bounded_integer j) -> int {
          return i>j.data;
        }
        template<class Integer0, Integer0 min0, Integer0 max0>
        friend constexpr auto
        operator>(bounded_integer i, bounded_integer<Integer0,min0,max0> j) -> int {
          return i.data>j.data;
        }
        // supérieur ou égal
        template<class Integer0> friend constexpr auto
        operator>=(bounded_integer i, Integer0 j) -> int {
          return i.data>=j;
        }
        template<class Integer0> friend constexpr auto
        operator>=(Integer0 i, bounded_integer j) -> int {
          return i>=j.data;
        }
        template<class Integer0, Integer0 min0, Integer0 max0>
        friend constexpr auto
        operator>=(bounded_integer i, bounded_integer<Integer0,min0,max0> j) -> int {
          return i.data>=j.data;
        }
     
      // arithmetique
        /// addition
        template<class Integer0> friend constexpr auto
        operator+(bounded_integer i, Integer0 j) -> int { // je renvoie en entier, mais on pourrait imaginer renvoyer 
                                                          // un type qui dépend des arguments
                                                          // (par exemple unsigned int si on a des arguments unsigned int)
                                                          // c'est ce que doit faire le compilateur Pascal lui-même
          return i.data + j;
        }
        template<class Integer0> friend constexpr auto
        operator+(Integer0 i, bounded_integer j) -> int {
          return j+i; // commutatif
        }
        template<class Integer0, Integer0 min0, Integer0 max0>
        friend constexpr auto
        operator+(bounded_integer i, bounded_integer<Integer0,min0,max0> j) -> int {
          return i.data + j.data;
        }
        /// soustraction
        template<class Integer0> friend constexpr auto
        operator-(bounded_integer i, Integer0 j) -> int {
          return i.data - j;
        }
        template<class Integer0> friend constexpr auto
        operator-(Integer0 i, bounded_integer j) -> int {
          return j-i; // commutatif
        }
        template<class Integer0, Integer0 min0, Integer0 max0>
        friend constexpr auto
        operator-(bounded_integer i, bounded_integer<Integer0,min0,max0> j) -> int {
          return i.data - j.data;
        }
        /// multiplication
        template<class Integer0> friend constexpr auto
        operator*(bounded_integer i, Integer0 j) -> int {
          return i.data * j;
        }
        template<class Integer0> friend constexpr auto
        operator*(Integer0 i, bounded_integer j) -> int {
          return j*i; // commutatif
        }
        template<class Integer0, Integer0 min0, Integer0 max0>
        friend constexpr auto
        operator*(bounded_integer i, bounded_integer<Integer0,min0,max0> j) -> int {
          return i.data * j.data;
        }
     
        /// division euclidienne
        template<class Integer0> friend constexpr auto
        operator/(bounded_integer i, Integer0 j) -> int {
          return i.data / j;
        }
        template<class Integer0> friend constexpr auto
        operator%(bounded_integer i, Integer0 j) -> int {
          return i.data % j;
        }
    };
     
     
    // ConvertirNombreEnChaine.h
    #include <string>
     
    using TEntierBorneParle = bounded_integer<int,0,99>;
    enum class TContexteLangue {
      clParDefaut, clFrance, clQuebec, clBelgique, clSuisseRomande, clSuisseRomandeGeneve, clSenegal
    };
    using TNombreEnChaine = std::string;
    using EConversionNombre = std::exception;
     
    auto
    ConvertirNombreEnChaine(TEntierBorneParle unEntier, TContexteLangue unContexte) -> TNombreEnChaine;
     
     
     
    // ConvertirNombreEnChaine.cpp
    using TUnites = bounded_integer<int,0,9>;
    using TUnitesComposees = bounded_integer<int,0,19>;
    using TDizainesNormales = bounded_integer<int,2,6>;
    using TDizaines = bounded_integer<int,0,9>;
     
     
      //séparateurs de nombres
    std::string rsEspaceNombre = " ";
    std::string rsTiretNombre  = "-";
    std::string rsEt           = " et ";
     
    //Unités:
    std::string rsZero            = "zéro";
    std::string rsUn              = "un";
    std::string rsDeux            = "deux";
    std::string rsTrois           = "trois";
    std::string rsQuatre          = "quatre";
    std::string rsCinq            = "cinq";
    std::string rsSix             = "six";
    std::string rsSept            = "sept";
    std::string rsHuit            = "huit";
    std::string rsNeuf            = "neuf";
    //Entre dix et dix-neuf
    std::string rsDix             = "dix";
    std::string rsOnze            = "onze";
    std::string rsDouze           = "douze";
    std::string rsTreize          = "treize";
    std::string rsQuatorze        = "quatorze";
    std::string rsQuinze          = "quinze";
    std::string rsSeize           = "seize";
    //dizaines
    std::string rsVingt           = "vingt";
    std::string rsTrente          = "trente";
    std::string rsQuarante        = "quarante";
    std::string rsCinquante       = "cinquante";
    std::string rsSoixante        = "soixante";
     
    //entiers par contexte..
    std::string rs70ParDefault    = "soixante-dix";
    std::string rs70Belge         = "septante";
     
    std::string rs80ParDefault    = "quatre-vingt";
    std::string rs80SuisseRomande = "huitante";
     
    std::string rs90ParDefault    = "quatre-vingt-dix";
    std::string rs90Belge         = "nonante";
     
    //messages d'erreur:
    class eUniteNonComprise : public std::exception {};
    class eDizaineNonComprise : public std::exception {};
    class eNombrePasCompris : public std::exception {};
     
    constexpr auto
    Unite(TEntierBorneParle unEntier) {
      return TUnites(unEntier%10);
    }
    constexpr auto
    Dizaine(TEntierBorneParle unEntier) {
      return TDizaines(unEntier/10);
    }
     
    constexpr auto
    DecomposerNombre(TEntierBorneParle unEntier) {
      return std::make_pair(Dizaine(unEntier),Unite(unEntier));
    }
     
     
    auto
    ConvertirNombreEntre0et9(TEntierBorneParle unEntier) -> TNombreEnChaine {
      if (unEntier==0) return rsZero;
      if (unEntier==1) return rsUn;
      if (unEntier==2) return rsDeux;
      if (unEntier==3) return rsTrois;
      if (unEntier==4) return rsQuatre;
      if (unEntier==5) return rsCinq;
      if (unEntier==6) return rsSix;
      if (unEntier==7) return rsSept;
      if (unEntier==8) return rsHuit;
      if (unEntier==9) return rsNeuf;
      else throw eUniteNonComprise();
    }
     
     
    auto
    ConvertirDizaines(TDizainesNormales uneDizaine) -> TNombreEnChaine {
      if (uneDizaine==2) return rsVingt;
      if (uneDizaine==3) return rsTrente;
      if (uneDizaine==4) return rsQuarante;
      if (uneDizaine==5) return rsCinquante;
      if (uneDizaine==6) return rsSoixante;
      else throw eDizaineNonComprise();
    }
     
     
    auto
    ComposerChainesDizainesEtUnites(TNombreEnChaine laDizaine, TNombreEnChaine lUnite) -> TNombreEnChaine {
      if (lUnite==rsZero) 
        return laDizaine;
      else if (((lUnite==rsUn) || (lUnite==rsOnze)) && (laDizaine!=rs80ParDefault))
        return laDizaine + rsEt + lUnite;
      else
        return laDizaine + rsTiretNombre + lUnite;
    }
     
     
    auto
    ConvertirNombreEntre10et19(TEntierBorneParle unEntier) -> TNombreEnChaine {
      if (unEntier==10) return rsDix;
      if (unEntier==11) return rsOnze;
      if (unEntier==12) return rsDouze;
      if (unEntier==13) return rsTreize;
      if (unEntier==14) return rsQuatorze;
      if (unEntier==15) return rsQuinze;
      if (unEntier==16) return rsSeize;
      if (17<=unEntier && unEntier<=19) return rsDix + rsTiretNombre + ConvertirNombreEntre0et9(TUnites(unEntier % 10));
      else throw eNombrePasCompris();
    }
     
     
    auto
    ConvertirNombreEntre20et69(TEntierBorneParle unEntier) -> TNombreEnChaine {
      auto [laDizaine,lUnite] = DecomposerNombre(unEntier);
      auto nbreDizaines = ConvertirDizaines(TDizainesNormales(laDizaine));
      auto nbreUnites = ConvertirNombreEntre0et9(lUnite);
      return ComposerChainesDizainesEtUnites(nbreDizaines, nbreUnites);
    }
     
     
    auto
    ConvertirNombreEntre70et79(TEntierBorneParle unEntier, TContexteLangue unContexte) -> TNombreEnChaine {
      // note, comme dans la version Pascal, la sureté de type est ici toute relative: si unEntier == 60, je peux appeler la fonction alors qu'elle a une précondition unEntier>=70
      switch (unContexte) {
        case TContexteLangue::clBelgique:
        case TContexteLangue::clSuisseRomande:
        case TContexteLangue::clSuisseRomandeGeneve: {
           TUnites lUnite = TUnites(unEntier - 70);
           TNombreEnChaine nbreDizaines = rs70Belge;
           TNombreEnChaine nbreUnites = ConvertirNombreEntre0et9(lUnite);
           return ComposerChainesDizainesEtUnites(nbreDizaines, nbreUnites);
        }
        default: {
           TEntierBorneParle lUnite = TEntierBorneParle(unEntier - 60);
           TNombreEnChaine nbreDizaines = rsSoixante;
           TNombreEnChaine nbreUnites = ConvertirNombreEntre10et19(lUnite);
           return ComposerChainesDizainesEtUnites(nbreDizaines, nbreUnites);
        }
      }
    }
     
    auto
    ConvertirNombreEntre80et89(TEntierBorneParle unEntier, TContexteLangue unContexte) -> TNombreEnChaine {
      auto lUnite = Unite(unEntier);
     
      TNombreEnChaine nbreDizaines;
      switch (unContexte) {
        case TContexteLangue::clSuisseRomande: {
          nbreDizaines = rs80SuisseRomande;
          break;
        }
        default: {
          nbreDizaines = rs80ParDefault;
        }
      }
      auto nbreUnites = ConvertirNombreEntre0et9(lUnite);
      return ComposerChainesDizainesEtUnites(nbreDizaines, nbreUnites);
    }
     
    auto
    ConvertirNombreEntre90et99(TEntierBorneParle unEntier, TContexteLangue unContexte) -> TNombreEnChaine {
      switch (unContexte) {
        case TContexteLangue::clBelgique:
        case TContexteLangue::clSuisseRomande:
        case TContexteLangue::clSuisseRomandeGeneve: {
           TUnites lUnite = TUnites(unEntier - 90);
           TNombreEnChaine nbreDizaines = rs90Belge;
           TNombreEnChaine nbreUnites = ConvertirNombreEntre0et9(lUnite);
           return ComposerChainesDizainesEtUnites(nbreDizaines, nbreUnites);
        }
        default: {
           TUnitesComposees lUnite = TUnitesComposees(unEntier - 80);
           TNombreEnChaine nbreDizaines = rs80ParDefault;
           TNombreEnChaine nbreUnites = ConvertirNombreEntre10et19(TEntierBorneParle(lUnite));
           return ComposerChainesDizainesEtUnites(nbreDizaines, nbreUnites);
        }
      }
    }
     
    auto
    ConvertirNombreEnChaine(TEntierBorneParle unEntier, TContexteLangue unContexte) -> TNombreEnChaine {
      if ( 0<=unEntier&& unEntier< 10) return   ConvertirNombreEntre0et9(unEntier);
      if (10<=unEntier&& unEntier< 20) return ConvertirNombreEntre10et19(unEntier);
      if (20<=unEntier&& unEntier< 70) return ConvertirNombreEntre20et69(unEntier);
      if (70<=unEntier&& unEntier< 80) return ConvertirNombreEntre70et79(unEntier, unContexte);
      if (80<=unEntier&& unEntier< 90) return ConvertirNombreEntre80et89(unEntier, unContexte);
      if (90<=unEntier&& unEntier<100) return ConvertirNombreEntre90et99(unEntier, unContexte);
      else throw eNombrePasCompris();
    }
     
     
    // main.cpp
    #include <iostream>
     
    int main() {
      for (auto contexte : {TContexteLangue::clFrance,TContexteLangue::clBelgique,TContexteLangue::clSuisseRomande}) {
        for (int i=0; i<100; ++i) {
          TEntierBorneParle ii(i);
          std::cout << ConvertirNombreEnChaine(ii,contexte) << "\n";
        }
        std::cout << "\n\n";
      }
      return 0;
    }


    À compiler et exécuter avec
    g++ -Wall -O3 -std=c++17 test.cpp && ./a.out

    Dites-moi ce que vous en pensez. En particulier, Pyramidev est-ce que ma classe template te convient ?

  8. #248
    Membre régulier
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2017
    Messages
    36
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

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

    Informations forums :
    Inscription : Août 2017
    Messages : 36
    Points : 95
    Points
    95
    Par défaut
    Ah oui et niveau perfo, je m'attendrais à ce que tout se passe comme si on manipulait des int (je n'ai pas regardé mais la classe template est juste un wrapper avec des fonctions inline qui ne font rien)

  9. #249
    Membre régulier
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2017
    Messages
    36
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

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

    Informations forums :
    Inscription : Août 2017
    Messages : 36
    Points : 95
    Points
    95
    Par défaut
    Pour détailler un peu mon approche préférée, sur la fonction ConvertirNombreEntre0et9, je ferais ça:

    Code c++ : 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
    31
    32
    33
    #include <exception>
    class precondition_failure : public std::exception {};
     
     
    template<class Func> constexpr auto
    // requière Func est appelable avec aucun argument et revoie un booléen
    precondition(Func f) -> void {
    #ifdef DEBUG
      if (!f()) throw precondition_failure();
    #endif
    }
     
     
    auto
    ConvertirNombreEntre0et9(int i) -> std::string {
      precondition([i](){ return 0<=i && i<10; }); // je passe une lambda comme préconditon. la syntaxe n'est pas parfaite mais bon...
      if (i==0) return rsZero;
      if (i==1) return rsUn;
      if (i==2) return rsDeux;
      if (i==3) return rsTrois;
      if (i==4) return rsQuatre;
      if (i==5) return rsCinq;
      if (i==6) return rsSix;
      if (i==7) return rsSept;
      if (i==8) return rsHuit;
      if (i==9) return rsNeuf;
      throw;
    }
     
    int main() {
      ConvertirNombreEntre0et9(-1);
      return 0;
    }

  10. #250
    Membre régulier
    Inscrit en
    Décembre 2004
    Messages
    123
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 123
    Points : 97
    Points
    97
    Par défaut
    Je vous remercie tous d'être capables de relire le source que j'ai fourni, source écrit en une heure à titre d'exemple. Je vous remercie également pour toutes les remarques de forme pour l'améliorer. Vous noterez également que toutes les remarques portent sur la partie du code à L'INTERIEUR de la clause implémentation, c'est-à-dire non visible de l'extérieur. L'IHM ajoute sa propre couche de protection, à la fois en entrée et en sortie, si jamais une exception est levée. Les différentes sécurités de Pascal se cumulent pour interdire tout plantage... moi, j'aime bien programmer un exemple qui ne plante pas en une seule heure...

    Veuillez noter également la complexité nécessaire en C++ pour remplacer une seule déclaration de type en Pascal...
    Je sais bien qu'on peut tout faire en utilisant les génériques, mais avoir dans sa boite à outil qu'un marteau, c'est limité...

    Veuillez noter également que personne n'a commenté le code ADA, qui est encore beaucoup plus sûr, dont le compilateur a détecté des erreurs qui n'ont pas été vues par les participants à ce fil de discussion.

    Je suis en train de préparer une version orientée-objet qui sera plus complète (elle intégrera les cardinaux et les ordinaux), et qui prend en compte toutes vos remarques qui sont parfaitement légitimes. Elle sera proposée dans ce fil de discussion comme un projet complet pour en permettre la vérification indépendante. Laissez-moi juste un peu de temps pour ce faire, car comme nous tous, j'ai une vie IRL.

    Bien cordialement et bonne fin de week-end,
    Thierryc

  11. #251
    Membre éprouvé
    Homme Profil pro
    Ingénieur R&D
    Inscrit en
    Mai 2016
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Ingénieur R&D
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2016
    Messages : 313
    Points : 1 237
    Points
    1 237
    Par défaut
    Citation Envoyé par _Bérenger_ Voir le message
    ...
    6. Finalement, il me semble que le code est un peu meilleur par rapport au code de Thierryc grâce à 3), mais je pense qu'il n'est pas bon. En effet, je pense que cette idée de faire reposer la sûreté des intervalles sur le système de type est mauvaise: c'est lourd est ça n'est pas exhaustif (cf. 4.). À mon avis, si on veut vraiment avoir plus de sûreté, il faut donner des préconditions dans chaque fonction qui en requière.
    ...
    A propos de préconditions, j'ai vu qu'il y avait quelque chose dans la norme Ada 2012.
    Voir ici, section 6.1.1, p155 :
    http://www.ada-auth.org/standards/rm...1/RM-Final.pdf
    Comme cette lecture est un peu aride, il y a un exemple ici :
    http://www.electronicdesign.com/dev-...-joy-contracts

  12. #252
    Membre expert

    Homme Profil pro
    Consultant
    Inscrit en
    Janvier 2006
    Messages
    1 376
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Consultant

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 376
    Points : 3 583
    Points
    3 583
    Par défaut
    Citation Envoyé par thierryc Voir le message
    Bonjour zecreator,
    Non, c'est une profonde erreur. L'informatique est une discipline comme les autres. Ce serait comme dire: il existe 2 type d'humains, les médecins et les autres.

    Les informaticiens sont, comme tous les autres métiers, aux service de leurs clients. Le client est humain, ce n'est pas la machine, qui n'est qu'un outil. Et comme tous les autres professionnels, un informaticien doit être capable de communiquer avec son client, qui par définition, N'est PAS un informaticien.

    Cette attitude est enfantine et préjudiciable à notre discipline, à notre crédibilité, au respect qui nous est dû par nos clients, au progrès du génie logiciel qui est bien en retard par rapport au matériel.

    Bien cordialement,
    Thierryc
    Thierryc, je crois que :

    1. Tu n'as pas d'humour
    2. Si tu relis les 3 pages précédentes et que tu vois là du langage courant, utilisé dans la vie de tous les jours entre 2 personnes, tu as un problème.
    3. Tu te surestimes beaucoup. Comparer ton métier à celui d'un médecin est une preuve que beaucoup de développeurs se pensent supérieurs aux autres (après tout, les autres ne sont que des utilisateurs, nous on est des dieux !). Pour info, lorsque ce sera la fin du monde, il vaut mieux avoir un médecin dans son équipe qu'un développeur... Un développeur, sans ordinateur, ça perd tout de suite de sa superbe, alors qu'un médecin...

    Bref, prends du recul avec ton métier de "service".
    "La révolution informatique fait gagner un temps fou aux hommes, mais ils le passent avec leur ordinateur !"

  13. #253
    Membre régulier
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2017
    Messages
    36
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

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

    Informations forums :
    Inscription : Août 2017
    Messages : 36
    Points : 95
    Points
    95
    Par défaut
    Citation Envoyé par zecreator Voir le message
    Comparer ton métier à celui d'un médecin est une preuve que beaucoup de développeurs se pensent supérieurs aux autres (après tout, les autres ne sont que des utilisateurs, nous on est des dieux !). Pour info, lorsque ce sera la fin du monde, il vaut mieux avoir un médecin dans son équipe qu'un développeur... Un développeur, sans ordinateur, ça perd tout de suite de sa superbe, alors qu'un médecin...
    Enfin par contre, si c'est la fin du monde, il y a de bonne chance que ça soit justement parce qu'un développeur n'a pas trop pris son métier au sérieux quand il a codé la procédure d'urgence d'une centrale nucléaire ou un truc du genre . Je ne sais pas si les programmeurs ont le pouvoir de sauver des vies, mais tuer des gens, je n'ai aucun doute.

    Je ne vois pas pourquoi les programmeurs devraient être considérés comme supérieurs ou inférieurs aux médecins. L'important c'est de bien faire son travail non ? Et on ne peut pas dénier le fait que si un programmeur fait mal son métier, c'est tout aussi délétère, voire plus.

    Citation Envoyé par thierryc Voir le message
    Veuillez noter également la complexité nécessaire en C++ pour remplacer une seule déclaration de type en Pascal...
    Après il faut voir que cette complexité vient du fait que le C++ ne fournit aucun type de base (en dehors des types primitifs). Je pense que pour être juste, il faudrait comparer bounded_integer avec la partie du compilateur Pascal qui s'occupe d'analyser ces types.
    Je reste de toute façon sur le sentiment que cette construction ne permet pas d'attraper beaucoup d'erreurs en pratique.

    Citation Envoyé par wolinn Voir le message
    A propos de préconditions, j'ai vu qu'il y avait quelque chose dans la norme Ada 2012.
    On en parle aussi pour le C++, peut-être en 2050 ils seront d'accord sur la façon de procéder (en étant optimiste ).

  14. #254
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 471
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 471
    Points : 6 110
    Points
    6 110
    Par défaut
    Citation Envoyé par _Bérenger_ Voir le message
    - la sureté de type en Pascal (pareil en C++) n'est pas du tout complète. Par exemple, ConvertirNombreEntre11et19, ConvertirNombreEntre70et79, ConvertirNombreEntre80et89, ConvertirNombreEntre90et99 ont toutes comme préconditions un nombre [11,19], [70,79]... mais cette précondition n'est pas forcée par le type puisque l'argument est dans tous les cas dans [0,99]
    - certaines fonctions lancent des exceptions si on dépasse les bornes (ex : ConvertirNombreEntre00et10) d'autres non (ex : ConvertirNombreEnChaine)

    [...]

    6. Finalement, il me semble que le code est un peu meilleur par rapport au code de Thierryc grâce à 3), mais je pense qu'il n'est pas bon. En effet, je pense que cette idée de faire reposer la sûreté des intervalles sur le système de type est mauvaise: c'est lourd est ça n'est pas exhaustif (cf. 4.). À mon avis, si on veut vraiment avoir plus de sûreté, il faut donner des préconditions dans chaque fonction qui en requière.

    [...]

    Dites-moi ce que vous en pensez. En particulier, Pyramidev est-ce que ma classe template te convient ?
    Il est possible de faire un contrôle quasi-exhaustif des bornes à la compilation.
    Voici une version modifiée du code, en gardant le même algorithme :
    Code c++ : 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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    // bounded_integer.h
    #include <cassert>
    #include <functional>
    #include <type_traits>
     
    template<class Integer, Integer min, Integer max>
    class bounded_integer {
        private:
            Integer data;
     
            template<class Integer0, Integer0 min0, Integer0 max0>
            friend class bounded_integer;
     
            // Constructeur privé car non sûr.
            // Si l'utilisateur de la classe veut créer un bounded_integer
            // à partir d'un entier dont on ne connaît pas les bornes, il
            // doit passer par la fonction statique unsafe_create.
            explicit constexpr
            bounded_integer(Integer i)
                : data(i)
            {
                assert(i >= min);
                assert(i <= max);
                    // Remarque : A la place de assert, on pourrait utiliser BOOST_ASSERT
                    // dont le comportement est personalisable.
                    // Mais, pour que les autres membres de developpez.net puissent compiler
                    // ce code, j'évite la dépendance à Boost.
            }
     
        public:
            bounded_integer(const bounded_integer&) = default;
            bounded_integer& operator=(const bounded_integer&) = default;
     
            // Conversion implicite car conversion sûre.
            template<class Integer0, Integer0 min0, Integer0 max0,
                std::enable_if_t<(min0>=min) && (max0<=max), int> = 0>
            constexpr
            bounded_integer(bounded_integer<Integer0,min0,max0> i) noexcept
                : data(i.data)
            {
            }
     
            // Création d'un bounded_integer sans vérifier les bornes à la compilation.
            static constexpr bounded_integer
            unsafe_create(Integer i)
            {
                assert(i >= min);
                assert(i <= max);
                return bounded_integer{i};
            }
     
            constexpr Integer
            value() const noexcept {
                return data;
            }
     
        // comparaisons
            /// égalité
            template<class Integer0> friend constexpr auto // on peut vouloir comparer à un nombre d'un autre type
            operator==(bounded_integer i, Integer0 j) noexcept -> bool {
                return i.data == j;
            }
            template<class Integer0> friend constexpr auto
            operator==(Integer0 i, bounded_integer j) noexcept -> bool {
                return j*i; // symetrique
            }
            template<class Integer0, Integer0 min0, Integer0 max0>
            friend constexpr auto
            operator==(bounded_integer i, bounded_integer<Integer0,min0,max0> j) noexcept -> bool { // specialisation
                return i.data == j.data;
            }
            /// inégalité
            template<class Integer0> friend constexpr auto
            operator!=(bounded_integer i, Integer0 j) noexcept -> bool {
                return !(i==j);
            }
            template<class Integer0> friend constexpr auto
            operator!=(Integer0 i, bounded_integer j) noexcept -> bool {
                return !(i==j);
            }
            template<class Integer0, Integer0 min0, Integer0 max0>
            friend constexpr auto
            operator!=(bounded_integer i, bounded_integer<Integer0,min0,max0> j) noexcept -> bool {
                return !(i==j);
            }
            /// inférieur
            template<class Integer0> friend constexpr auto
            operator<(bounded_integer i, Integer0 j) noexcept -> bool {
                return i.data<j;
            }
            template<class Integer0> friend constexpr auto
            operator<(Integer0 i, bounded_integer j) noexcept -> bool {
                return i<j.data;
            }
            template<class Integer0, Integer0 min0, Integer0 max0>
            friend constexpr auto
            operator<(bounded_integer i, bounded_integer<Integer0,min0,max0> j) noexcept -> bool {
                return i.data<j.data;
            }
            // inf ou égal
            template<class Integer0> friend constexpr auto
            operator<=(bounded_integer i, Integer0 j) noexcept -> bool {
                return i.data<=j;
            }
            template<class Integer0> friend constexpr auto
            operator<=(Integer0 i, bounded_integer j) noexcept -> bool {
                return i<=j.data;
            }
            template<class Integer0, Integer0 min0, Integer0 max0>
            friend constexpr auto
            operator<=(bounded_integer i, bounded_integer<Integer0,min0,max0> j) noexcept -> bool {
                return i.data<=j.data;
            }
            // supérieur
            template<class Integer0> friend constexpr auto
            operator>(bounded_integer i, Integer0 j) noexcept -> bool {
                return i.data>j;
            }
            template<class Integer0> friend constexpr auto
            operator>(Integer0 i, bounded_integer j) noexcept -> bool {
                return i>j.data;
            }
            template<class Integer0, Integer0 min0, Integer0 max0>
            friend constexpr auto
            operator>(bounded_integer i, bounded_integer<Integer0,min0,max0> j) noexcept -> bool {
                return i.data>j.data;
            }
            // supérieur ou égal
            template<class Integer0> friend constexpr auto
            operator>=(bounded_integer i, Integer0 j) noexcept -> bool {
                return i.data>=j;
            }
            template<class Integer0> friend constexpr auto
            operator>=(Integer0 i, bounded_integer j) noexcept -> bool {
                return i>=j.data;
            }
            template<class Integer0, Integer0 min0, Integer0 max0>
            friend constexpr auto
            operator>=(bounded_integer i, bounded_integer<Integer0,min0,max0> j) noexcept -> bool {
                return i.data>=j.data;
            }
     
        // arithmetique
            /// addition
            template<class Integer0> friend constexpr auto
            operator+(bounded_integer i, Integer0 j) -> int { // je renvoie en entier, mais on pourrait imaginer renvoyer
                                                              // un type qui dépend des arguments
                                                              // (par exemple unsigned int si on a des arguments unsigned int)
                                                              // c'est ce que doit faire le compilateur Pascal lui-même
                return i.data + j;
            }
            template<class Integer0> friend constexpr auto
            operator+(Integer0 i, bounded_integer j) -> int {
                return j+i; // commutatif
            }
            template<class Integer0, Integer0 min0, Integer0 max0>
            friend constexpr auto
            operator+(bounded_integer i, bounded_integer<Integer0,min0,max0> j) -> int {
                return i.data + j.data;
            }
            /// soustraction
            template<class Integer0> friend constexpr auto
            operator-(bounded_integer i, Integer0 j) -> int {
                return i.data - j;
            }
            template<class Integer0> friend constexpr auto
            operator-(Integer0 i, bounded_integer j) -> int {
                return j-i; // commutatif
            }
            template<class Integer0, Integer0 min0, Integer0 max0>
            friend constexpr auto
            operator-(bounded_integer i, bounded_integer<Integer0,min0,max0> j) -> int {
                return i.data - j.data;
            }
            /// multiplication
            template<class Integer0> friend constexpr auto
            operator*(bounded_integer i, Integer0 j) -> int {
                return i.data * j;
            }
            template<class Integer0> friend constexpr auto
            operator*(Integer0 i, bounded_integer j) -> int {
                return j*i; // commutatif
            }
            template<class Integer0, Integer0 min0, Integer0 max0>
            friend constexpr auto
            operator*(bounded_integer i, bounded_integer<Integer0,min0,max0> j) -> int {
                return i.data * j.data;
            }
     
            /// division euclidienne
            template<class Integer0> friend constexpr auto
            operator/(bounded_integer i, Integer0 j) -> int {
                return i.data / j;
            }
            template<class Integer0> friend constexpr auto
            operator%(bounded_integer i, Integer0 j) -> int {
                return i.data % j;
            }
     
            template<Integer N>
            constexpr bounded_integer<Integer, min-N, max-N>
            minus() const {
                return bounded_integer<Integer, min-N, max-N>(data - N);
            }
     
            template<Integer N, std::enable_if_t<(N > 0), int> = 0>
            constexpr bounded_integer<Integer, min/N, max/N>
            divide() const {
                return bounded_integer<Integer, min/N, max/N>(data / N);
            }
     
            template<Integer N, std::enable_if_t<(min >= 0 && N > 0), int> = 0>
            constexpr bounded_integer<Integer, 0, N-1>
            modulo() const {
                return bounded_integer<Integer, 0, N-1>(data % N);
            }
     
            /// Si data < N, alors exécuter la routine en 1er paramètre, sinon celle en 2e.
            template<Integer N, class CallableX, class CallableY,
                std::enable_if_t<(min < N && N <= max), int> = 0>
            constexpr decltype(auto)
            if_less_than_then_else(CallableX&& whenLessThanN, CallableY&& otherwise) const
            {
                return (data < N) ?
                    std::invoke(std::forward<CallableX>(whenLessThanN), bounded_integer<Integer, min, N-1>{data}) :
                    std::invoke(std::forward<CallableY>(otherwise),     bounded_integer<Integer, N,   max>{data});
            }
    };
     
     
    // ConvertirNombreEnChaine.h
    #include <string>
     
    enum class TContexteLangue {
        clParDefaut, clFrance, clQuebec, clBelgique, clSuisseRomande, clSuisseRomandeGeneve, clSenegal
    };
    using TNombreEnChaine = std::string;
     
     
    // ConvertirNombreEnChaine.cpp
     
        //séparateurs de nombres
    std::string rsEspaceNombre = " ";
    std::string rsTiretNombre  = "-";
    std::string rsEt           = " et ";
     
    //Unités:
    std::string rsZero   = "zéro";
    std::string rsUn     = "un";
    std::string rsDeux   = "deux";
    std::string rsTrois  = "trois";
    std::string rsQuatre = "quatre";
    std::string rsCinq   = "cinq";
    std::string rsSix    = "six";
    std::string rsSept   = "sept";
    std::string rsHuit   = "huit";
    std::string rsNeuf   = "neuf";
    //Entre dix et dix-neuf
    std::string rsDix      = "dix";
    std::string rsOnze     = "onze";
    std::string rsDouze    = "douze";
    std::string rsTreize   = "treize";
    std::string rsQuatorze = "quatorze";
    std::string rsQuinze   = "quinze";
    std::string rsSeize    = "seize";
    //dizaines
    std::string rsVingt     = "vingt";
    std::string rsTrente    = "trente";
    std::string rsQuarante  = "quarante";
    std::string rsCinquante = "cinquante";
    std::string rsSoixante  = "soixante";
     
    //entiers par contexte..
    std::string rs70ParDefault = "soixante-dix";
    std::string rs70Belge      = "septante";
     
    std::string rs80ParDefault    = "quatre-vingt";
    std::string rs80SuisseRomande = "huitante";
     
    std::string rs90ParDefault = "quatre-vingt-dix";
    std::string rs90Belge      = "nonante";
     
    auto
    ConvertirNombreEntre0et9(bounded_integer<int, 0, 9> unEntier) -> TNombreEnChaine {
        if (unEntier==0) return rsZero;
        if (unEntier==1) return rsUn;
        if (unEntier==2) return rsDeux;
        if (unEntier==3) return rsTrois;
        if (unEntier==4) return rsQuatre;
        if (unEntier==5) return rsCinq;
        if (unEntier==6) return rsSix;
        if (unEntier==7) return rsSept;
        if (unEntier==8) return rsHuit;
        return rsNeuf;
    }
     
     
    auto
    ConvertirDizaines(bounded_integer<int, 2, 6> uneDizaine) -> TNombreEnChaine {
        if (uneDizaine==2) return rsVingt;
        if (uneDizaine==3) return rsTrente;
        if (uneDizaine==4) return rsQuarante;
        if (uneDizaine==5) return rsCinquante;
        return rsSoixante;
    }
     
     
    auto
    ComposerChainesDizainesEtUnites(TNombreEnChaine laDizaine, TNombreEnChaine lUnite) -> TNombreEnChaine {
        if (lUnite==rsZero)
            return laDizaine;
        else if (((lUnite==rsUn) || (lUnite==rsOnze)) && (laDizaine!=rs80ParDefault))
            return laDizaine + rsEt + lUnite;
        else
            return laDizaine + rsTiretNombre + lUnite;
    }
     
     
    auto
    ConvertirNombreEntre10et19(bounded_integer<int, 10, 19> unEntier) -> TNombreEnChaine {
        if (unEntier==10) return rsDix;
        if (unEntier==11) return rsOnze;
        if (unEntier==12) return rsDouze;
        if (unEntier==13) return rsTreize;
        if (unEntier==14) return rsQuatorze;
        if (unEntier==15) return rsQuinze;
        if (unEntier==16) return rsSeize;
        return rsDix + rsTiretNombre + ConvertirNombreEntre0et9(unEntier.modulo<10>());
    }
     
     
    auto
    ConvertirNombreEntre20et69(bounded_integer<int, 20, 69> unEntier) -> TNombreEnChaine {
        auto laDizaine = unEntier.divide<10>();
        auto lUnite    = unEntier.modulo<10>();
        auto nbreDizaines = ConvertirDizaines(laDizaine);
        auto nbreUnites = ConvertirNombreEntre0et9(lUnite);
        return ComposerChainesDizainesEtUnites(nbreDizaines, nbreUnites);
    }
     
     
    auto
    ConvertirNombreEntre70et79(bounded_integer<int, 70, 79> unEntier, TContexteLangue unContexte) -> TNombreEnChaine {
        switch (unContexte) {
            case TContexteLangue::clBelgique:
            case TContexteLangue::clSuisseRomande:
            case TContexteLangue::clSuisseRomandeGeneve: {
                auto lUnite = unEntier.minus<70>();
                TNombreEnChaine nbreDizaines = rs70Belge;
                TNombreEnChaine nbreUnites = ConvertirNombreEntre0et9(lUnite);
                return ComposerChainesDizainesEtUnites(nbreDizaines, nbreUnites);
            }
            default: {
                auto lUnite = unEntier.minus<60>();
                TNombreEnChaine nbreDizaines = rsSoixante;
                TNombreEnChaine nbreUnites = ConvertirNombreEntre10et19(lUnite);
                return ComposerChainesDizainesEtUnites(nbreDizaines, nbreUnites);
            }
        }
    }
     
    auto
    ConvertirNombreEntre80et89(bounded_integer<int, 80, 89> unEntier, TContexteLangue unContexte) -> TNombreEnChaine {
        auto lUnite = unEntier.modulo<10>();
        TNombreEnChaine nbreDizaines;
        switch (unContexte) {
            case TContexteLangue::clSuisseRomande: {
                nbreDizaines = rs80SuisseRomande;
                break;
            }
            default: {
                nbreDizaines = rs80ParDefault;
            }
        }
        auto nbreUnites = ConvertirNombreEntre0et9(lUnite);
        return ComposerChainesDizainesEtUnites(nbreDizaines, nbreUnites);
    }
     
    auto
    ConvertirNombreEntre90et99(bounded_integer<int, 90, 99> unEntier, TContexteLangue unContexte) -> TNombreEnChaine {
        switch (unContexte) {
            case TContexteLangue::clBelgique:
            case TContexteLangue::clSuisseRomande:
            case TContexteLangue::clSuisseRomandeGeneve: {
                auto lUnite = unEntier.minus<90>();
                TNombreEnChaine nbreDizaines = rs90Belge;
                TNombreEnChaine nbreUnites = ConvertirNombreEntre0et9(lUnite);
                return ComposerChainesDizainesEtUnites(nbreDizaines, nbreUnites);
            }
            default: {
                auto lUnite = unEntier.minus<80>();
                TNombreEnChaine nbreDizaines = rs80ParDefault;
                TNombreEnChaine nbreUnites = ConvertirNombreEntre10et19(lUnite);
                return ComposerChainesDizainesEtUnites(nbreDizaines, nbreUnites);
            }
        }
    }
     
    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wshadow" // Le masquage avec unEntier est volontaire.
     
    auto
    ConvertirNombreEnChaine(bounded_integer<int, 0, 99> unEntier, TContexteLangue unContexte) -> TNombreEnChaine {
        return unEntier.if_less_than_then_else<10>(
            [&](bounded_integer<int, 0, 9> unEntier) {
                return ConvertirNombreEntre0et9(unEntier);
            },
            [&](bounded_integer<int, 10, 99> unEntier) {
                return unEntier.if_less_than_then_else<20>(
                    [&](bounded_integer<int, 10, 19> unEntier) {
                        return ConvertirNombreEntre10et19(unEntier);
                    },
                    [&](bounded_integer<int, 20, 99> unEntier) {
                        return unEntier.if_less_than_then_else<70>(
                            [&](bounded_integer<int, 20, 69> unEntier) {
                                return ConvertirNombreEntre20et69(unEntier);
                            },
                            [&](bounded_integer<int, 70, 99> unEntier) {
                                return unEntier.if_less_than_then_else<80>(
                                    [&](bounded_integer<int, 70, 79> unEntier) {
                                        return ConvertirNombreEntre70et79(unEntier, unContexte);
                                    },
                                    [&](bounded_integer<int, 80, 99> unEntier) {
                                        return unEntier.if_less_than_then_else<90>(
                                            [&](bounded_integer<int, 80, 89> unEntier) {
                                                return ConvertirNombreEntre80et89(unEntier, unContexte);
                                            },
                                            [&](bounded_integer<int, 90, 99> unEntier) {
                                                return ConvertirNombreEntre90et99(unEntier, unContexte);
                                            }
                                        );
                                    }
                                );
                            }
                        );
                    }
                );
            }
        );
    }
     
    #pragma GCC diagnostic pop
     
    // main.cpp
    #include <iostream>
     
    int main() {
        for (auto contexte : {TContexteLangue::clFrance,TContexteLangue::clBelgique,TContexteLangue::clSuisseRomande}) {
            for (int i=0; i<100; ++i) {
                auto ii = bounded_integer<int, 0, 99>::unsafe_create(i);
                std::cout << ConvertirNombreEnChaine(ii, contexte) << "\n";
            }
            std::cout << "\n\n";
        }
        return 0;
    }

    Parmi les changements que j'ai effectués, voici les plus importants :
    • Pour que l'utilisateur construise un bounded_integer en passant outre le contrôle à la compilation sur les bornes, il est obligé de passer par la fonction statique template unsafe_create.
    • Dans bounded_integer, j'ai ajouté les fonctions membres templates minus, divide, modulo et if_less_than_then_else qui permettent de réduire les cas où l'utilisateur appelle unsafe_create. D'ailleurs, il n'y a plus qu'un seul endroit où l'utilisateur de la classe appelle unsafe_create : une boucle for de la fonction main.
    • Comme toutes les bornes sont contrôlées à la compilation (sauf dans un seul appel de la fonction unsafe_create), les contrôles au runtime qui lançaient une exception en cas de non respect des bornes ne sont plus utiles, donc je les ai supprimés.


    A présent, tout est très sécurisé. Cela dit, dans ConvertirNombreEnChaine, je regrette la baisse de lisibilité induite par l'utilisation de bounded_integer::if_less_than_then_else.

    Rq : Ceux qui veulent compiler le code sans télécharger un compilateur C++ peuvent utiliser le compilateur en ligne : http://coliru.stacked-crooked.com/

  15. #255
    Membre émérite
    Homme Profil pro
    Ingénieur en génie logiciel
    Inscrit en
    Juin 2012
    Messages
    860
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Ingénieur en génie logiciel
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Juin 2012
    Messages : 860
    Points : 2 449
    Points
    2 449
    Par défaut
    Citation Envoyé par _Bérenger_ Voir le message
    Plus sérieusement ceci dit, je ne suis pas sûr que citer Microsoft, dont le code source est notoirement incompréhensible, soit un argument recevable. On entend moins souvent parler de Facebook et Google en ce qui concerne la qualité du code, mais je ne doute pas qu'elle soit assez faible.

    regarder un peu les msg sur la mailing du kernel linux quand google a tenté de pousser du code d'android à ses débuts...

  16. #256
    Membre extrêmement actif
    Avatar de Madmac
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2004
    Messages
    1 685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

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

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 685
    Points : 1 376
    Points
    1 376
    Billets dans le blog
    7
    Par défaut
    Citation Envoyé par _Bérenger_ Voir le message


    Je ne veux pas nier l'importance des contributions de Wirth à la programmation. Mais je ne pense pas qu'il faille dire pour autant que Oberon OS est à utiliser maintenant. Exemple similaire: Dijkstra et THE OS. Il y avait certainement plein de bonnes idées dans cet OS, mais c'était un essai de recherche, pas un programme destiner à durer.
    Uniquement, parce que la technologie ne permettait pas, à l'époque, de solution comme Erlang. Erlang demande l'installation d'une machine virtuelle. Oberon serait encore une très bonne option pour faire du groupware. Comme je l'ai mentionné, il est possible d'avoir le langage, mais c'est une version limité du langage. Mais des projets d'importance comme le F35, Erlang aurait été le meilleur choix.

    Joe Armstrong remarked in an interview with Rackspace in 2013: “If Java is 'write once, run anywhere', then Erlang is 'write once, run forever'.”[14]

  17. #257
    Membre expert

    Homme Profil pro
    Consultant
    Inscrit en
    Janvier 2006
    Messages
    1 376
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Consultant

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 376
    Points : 3 583
    Points
    3 583
    Par défaut
    Citation Envoyé par _Bérenger_ Voir le message
    Enfin par contre, si c'est la fin du monde, il y a de bonne chance que ça soit justement parce qu'un développeur n'a pas trop pris son métier au sérieux quand il a codé la procédure d'urgence d'une centrale nucléaire ou un truc du genre . Je ne sais pas si les programmeurs ont le pouvoir de sauver des vies, mais tuer des gens, je n'ai aucun doute.
    C'est clair. Mettre autant de responsabilités entre les mains des développeurs informatique. C'est déjà le début des problèmes et faut être totalement inconscient. Comme y a pas un développeur qui puisse être d'accord avec les autres, du coup le boulot sera obligatoirement salopé

    Citation Envoyé par _Bérenger_ Voir le message
    Je ne vois pas pourquoi les programmeurs devraient être considérés comme supérieurs ou inférieurs aux médecins. L'important c'est de bien faire son travail non ?
    Je pourrais être d'accord si la plupart des développeurs admettaient que parfois, c'est de leur faute. Malheureusement, beaucoup mettent les bugs sur le compte :

    - de l'utilisateur final (qui est vraiment une bûche en informatique et qu'il devrait plutôt utiliser une machine à écrire, mieux un stylo)
    - du framework utilisé sur lequel il n'ont aucun contrôle (sauf quand leur code marche bien, là, ils maîtrisent parfaitement !)
    - d'un management bidon et un chef de projet à la ramasse (ce con là...)
    - de collègues qui ont dû toucher son code derrière son dos ('culés d'collègues)
    - d'un salaire trop bas pour prendre ses responsabilités (INSERT COIN)

    Attention, je ne dis pas ça au hasard, c'est du vécu. J'ai fais 5 boites, et j'ai toujours rencontré ce profil. Le dev qui est persuadé que l'erreur, ceux sont les autres.

    Et au final, si on le titille trop, il est capable d'aller se vendre ailleurs en laissant plein de cadavres derrière lui (ça aussi c'est du vécu).
    "La révolution informatique fait gagner un temps fou aux hommes, mais ils le passent avec leur ordinateur !"

  18. #258
    Membre régulier
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2017
    Messages
    36
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

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

    Informations forums :
    Inscription : Août 2017
    Messages : 36
    Points : 95
    Points
    95
    Par défaut
    Citation Envoyé par marc.collin Voir le message
    regarder un peu les msg sur la mailing du kernel linux quand google a tenté de pousser du code d'android à ses débuts...
    As-tu la référence ? Je ne sais pas à quoi faisait référence cette conversation. Je prenais l'exemple de Microsoft mais ce n'était pas pour dire que le code de Linux est particulièrement propre.

  19. #259
    Membre régulier
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2017
    Messages
    36
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

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

    Informations forums :
    Inscription : Août 2017
    Messages : 36
    Points : 95
    Points
    95
    Par défaut
    Citation Envoyé par zecreator Voir le message
    Je pourrais être d'accord si la plupart des développeurs admettaient que parfois, c'est de leur faute. Malheureusement, beaucoup mettent les bugs sur le compte :

    - de l'utilisateur final (qui est vraiment une bûche en informatique et qu'il devrait plutôt utiliser une machine à écrire, mieux un stylo)
    - du framework utilisé sur lequel il n'ont aucun contrôle (sauf quand leur code marche bien, là, ils maîtrisent parfaitement !)
    - d'un management bidon et un chef de projet à la ramasse (ce con là...)
    - de collègues qui ont dû toucher son code derrière son dos ('culés d'collègues)
    - d'un salaire trop bas pour prendre ses responsabilités (INSERT COIN)
    Je pense qu'on est d'accord. Ce que je veux dire c'est qu'il faut prendre l'activité de programmation au sérieux, autant que la médecine. Tu dis que les programmeurs devraient se sentir responsables, comme les médecins, mais que bien souvent ils n'endossent pas cette responsabilité : je suis d'accord et il n'y a pas de contradiction. Mais je dirais même que plus on (j'inclus tout le monde : programmeurs et non-programmeurs) prend la programmation au sérieux, plus on incite les développeurs à être sérieux.

  20. #260
    Membre expert

    Homme Profil pro
    Consultant
    Inscrit en
    Janvier 2006
    Messages
    1 376
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Consultant

    Informations forums :
    Inscription : Janvier 2006
    Messages : 1 376
    Points : 3 583
    Points
    3 583
    Par défaut
    Citation Envoyé par _Bérenger_ Voir le message
    Tu dis que les programmeurs devraient se sentir responsables, comme les médecins, mais que bien souvent ils n'endossent pas cette responsabilité : je suis d'accord et il n'y a pas de contradiction. Mais je dirais même que plus on (j'inclus tout le monde : programmeurs et non-programmeurs) prend la programmation au sérieux, plus on incite les développeurs à être sérieux.
    Après, c'est aussi le contexte hyper productif que les entreprises imposent aux développeurs. Etre rapide et efficace pour tenir des délais très très serrés.

    Quand je vois le programme des formations en école d'ingé... On leur apprend surtout à configurer des frameworks, à savoir lancer une chaîne de compilation. Il y a très peu de temps sur la compréhension de ce qu'ils codent. On demande beaucoup de travail personnel aux étudiants, sur des choses qui devraient être vues en cours (comme la syntaxe, le vocabulaire d'un langage...). Leur formation, c'est 45% de l'auto-formation. Et arrivé sur le terrain, on voit les dégats...
    "La révolution informatique fait gagner un temps fou aux hommes, mais ils le passent avec leur ordinateur !"

Discussions similaires

  1. Pourquoi les langages interprétés sont-ils préférés pour l'analyse de données ?
    Par User23 dans le forum Statistiques, Data Mining et Data Science
    Réponses: 1
    Dernier message: 12/05/2016, 21h18
  2. Les langages statiques sont-ils trop sophistiqués et complexes ?
    Par Katleen Erna dans le forum Actualités
    Réponses: 53
    Dernier message: 20/01/2013, 10h06
  3. Réponses: 2
    Dernier message: 11/05/2010, 19h36
  4. Réponses: 2
    Dernier message: 06/05/2007, 22h37
  5. Pourquoi les mails ne sont ils pas envoyés?
    Par Sunsawe dans le forum Développement
    Réponses: 3
    Dernier message: 12/04/2007, 23h49

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